我正在使用Spring Data JPA和Hibernate映射开发一个Spring Boot门户网站,我发现在理解其他人实现的以下代码的确切工作方式时遇到了一些困难(它工作得很好,但JPA\Hibernate不是我喜欢的,我缺少了一些东西)。
在数据库上我有这个
门户用户
表示我的应用程序的用户的表
如您所见,此表包含
parent_id
的FK字段
门户用户
表本身。这用于在用户与其父级之间创建递归关系(您可以看到这是一种经典的引用关系:父级是将另一个用户带入系统的用户)。
这
门户用户
DB表已映射到此
使用者
实体类:
@Entity
@Table(name = "portal_user")
@Getter
@Setter
public class User implements Serializable {
private static final long serialVersionUID = 5062673109048808267L;
@Id
@Column(name = "id")
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
@Column(name = "first_name")
@NotNull(message = "{NotNull.User.firstName.Validation}")
private String firstName;
@Column(name = "middle_name")
private String middleName;
@Column(name = "surname")
@NotNull(message = "{NotNull.User.surname.Validation}")
private String surname;
@Column(name = "sex")
@NotNull(message = "{NotNull.User.sex.Validation}")
private char sex;
@Column(name = "birthdate")
@NotNull(message = "{NotNull.User.birthdate.Validation}")
private Date birthdate;
@Column(name = "tax_code")
@NotNull(message = "{NotNull.User.taxCode.Validation}")
private String taxCode;
@Column(name = "e_mail")
@NotNull(message = "{NotNull.User.email.Validation}")
private String email;
@Column(name = "pswd")
@NotNull(message = "{NotNull.User.pswd.Validation}")
private String pswd;
@Column(name = "contact_number")
@NotNull(message = "{NotNull.User.contactNumber.Validation}")
private String contactNumber;
@Temporal(TemporalType.DATE)
@Column(name = "created_at")
private Date createdAt;
@Column(name = "is_active")
private boolean is_active;
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "user", orphanRemoval = true)
@JsonManagedReference
private Set<Address> addressesList = new HashSet<>();
@ManyToMany(cascade = { CascadeType.MERGE })
@JoinTable(
name = "portal_user_user_type",
joinColumns = { @JoinColumn(name = "portal_user_id_fk") },
inverseJoinColumns = { @JoinColumn(name = "user_type_id_fk") }
)
Set<UserType> userTypes;
@ManyToOne(fetch = FetchType.EAGER)
@JsonProperty("subagent")
private User parent;
public User() {
super();
// TODO Auto-generated constructor stub
}
public User(String firstName, String middleName, String surname, char sex, Date birthdate, String taxCode,
String email, String pswd, String contactNumber, Date createdAt, boolean is_active) {
super();
this.firstName = firstName;
this.middleName = middleName;
this.surname = surname;
this.sex = sex;
this.birthdate = birthdate;
this.taxCode = taxCode;
this.email = email;
this.pswd = pswd;
this.contactNumber = contactNumber;
this.createdAt = createdAt;
this.is_active = is_active;
}
}
尤其是这种关系似乎是由这个领域来处理的:
@ManyToOne(fetch = FetchType.EAGER)
@JsonProperty("subagent")
private User parent;
然后,我使用此服务方法将一个新对象插入
门户用户
表,考虑到
parent_id
可以设置字段:
@Override
@Transactional
public User insertClientUser(User clientUser) throws DuplicateException, SubAgentUserNotExist, NotFoundException {
String subAgentEmail = null;
if(clientUser.getParent() != null) subAgentEmail = clientUser.getParent().getEmail();
User checkClientUserExist = this.getUserByemail(clientUser.getEmail());
if (checkClientUserExist != null) {
String MsgErr = String.format("User %s already registered in the system !!! "
+ "Impossible to use POST", clientUser.getEmail());
log.warning(MsgErr);
throw new DuplicateException(MsgErr);
}
log.info(String.format("UserServiceImpl --> insertClientUser client user: %s %s - subagent email: %s ",
clientUser.getFirstName(), clientUser.getSurname(), subAgentEmail));
// check if present because we could add a user without assigned subagent
if(subAgentEmail != null) {
User subAgentUser = this.getUserByemail(subAgentEmail);
if (subAgentUser == null) {
String errorMessage = String.format("Subagent user %s doesn't exist in the sistem !!! "
+ "Impossible to use POST", subAgentEmail);
log.warning(errorMessage);
throw new SubAgentUserNotExist(errorMessage);
}
clientUser.setParent(subAgentUser);
}
User insertedClientUser = userRepository.save(clientUser);
return insertedClientUser;
}
注意:
这个
客户
是我作为的新记录插入的用户
门户用户
DB表,而
子代理用户
是一个仍然存在于这个DB表中的用户,它将是我插入的用户的父级。
所以基本上,在我的
门户用户
表中,我将有一个新记录(客户端用户),该记录具有
parent_id
它将包含子代理用户的ID。
这种方法的工作原理非常简单:
-
检查我必须插入的当前用户是否不存在于
门户用户
桌子如果用户还不存在于表中,则意味着必须插入该用户。
-
它检索子代理用户(
父母亲
)调用另一个服务方法并将其设置为
父母亲
属性。
-
最终,它将此客户端用户保存到
门户用户
DB表。
好吧,这一切都很正常,但我不明白Hibernate是如何正确设置
parent_id
字段。这
parent_id
字段包含父对象的PK(检索到的
子代理用户
对象
如果我探索我的
门户用户
表在执行了之前的服务方法后,我发现了我所期望的:
最后一行是插入的对象。正如您所看到的
parent_id
FK字段是53,它是同一表中预期父用户的PK。
它很好用,但我不明白怎么回事。谁告诉Hibernate如何设置此FK的值?特别是我感到困惑,因为似乎没有明确的映射到我的
使用者
实体类,实际上我有:
@ManyToOne(fetch=FetchType.EAGER)
@JsonProperty(“子代理”)
私有用户家长;
那么我错过了什么?它究竟是如何工作的?