我正在使用Spring和Hibernate映射开发Spring门户,并且我在试图理解由其他人实现的以下代码时遇到了一些困难(它运行得很好,但是JPA\Hibernate不是我的茶,我遗漏了一些东西)。
在数据库中,我有一个表示应用程序用户的portal_user表。

如您所见,此表包含parent_id字段,该字段是portal_user表本身的FK。这用于在用户与其父用户之间创建递归关系(您可以看到这是一种典型的参考关系:父用户是将另一个用户引入系统的用户)。
此portal_user 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;然后,我使用这个服务方法将一个新对象插入到portal_user表中,同时考虑到可以设置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;
}注意:subAgentUser客户端是我作为portal_user DB表的新记录插入的用户,而客户端是尚未存在于此DB表中的用户,它将是我插入的用户的父级。因此,基本上,在我的portal_user表上,我将有一个新记录(客户机用户),它具有包含子代理用户ID的parent_id。
这个方法的工作原理非常简单:
最后,
中。
好的,这一切都很有效,但是我不明白Hibernate是如何正确地设置这个新插入方法的parent_id字段的值的。这个parent_id字段包含父对象(检索的parent_id对象)的PK。
如果我在执行前一个服务方法之后探索我的portal_user表,我就会发现我所期望的:

最后一行是插入的对象。如您所见,parent_id FK字段的值为53,即相同表中预期父用户的PK。
它很好,但我不明白它是怎么回事。谁说冬眠如何设置这个FK的值?特别是,我是confuserd,因为似乎没有将该字段显式映射到我的用户实体类中,实际上我有:
@ManyToOne(fetch = FetchType.EAGER)
@JsonProperty("subagent")
private User parent;那我错过了什么?它到底是怎么工作的?
发布于 2022-01-06 06:17:29
在Hibernate中,@ManyToOne为另一个具有多重性的实体类指定了一个单值关联。在这种情况下,它与同一实体相关联。
ORM将数据从对象模型映射到关系模型,反之亦然。因此,这些关系是使用实体映射的。这有助于我们轻松地从父对象遍历到子对象。我们可以构建多个嵌套关系,可以通过使用点和链接方法遍历来查询或创建对象。
众所周知,每个实体都有自己的生命周期,一旦设置了关联,Hibernate就会将外键映射为关联实体的主标识符。在这里,它分配给id列,这是一个主键。但是,可以使用@JoinColumn注释对其进行定制。
下面是Hibernate在创建portal_user表以设置关联之后生成的sql。
alter table portal_user
add constraint FKdgqt4pnsjho6u58mtnackj4h8
foreign key (parent_id)
references portal_user当subAgentUser实体设置为clientUser时,hibernate使用parent_id列将记录映射到关联实体(SubAgentUser)的主要标识符,同时刷新查询.
clientUser.setParent(subAgentUser);https://stackoverflow.com/questions/70600779
复制相似问题