我一直在尝试使用JPA / Hibernate建立一个相当简单的父子关系,尽管有很多教程和文章,但我仍然无法使其正常工作。
我有一个带有数字ID的Customer实体,其中包含一个Address实体列表。地址实体具有一个复合密钥,该复合密钥由客户ID上的外键和使其唯一的序列号组成(但仅在客户ID的上下文中)。
我希望能够对Customer实体执行经典的CRUD操作,这也应该反映给Address实体(例如,当我在客户列表中添加,更新或删除地址时)。
@Entity(name = "Customer ")
@Table(name = "customer ")
@DynamicUpdate
public class Customer implements Serializable
{
@Id
@Column(name = "id", nullable = false)
private Long id;
@OneToMany(mappedBy = "customer", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
private List<Address> addresses;
@Override public boolean equals(Object obj)
{
return obj instanceof Customer && ((Customer ) obj).getId() == this.getId();
}
}
-
@Entity(name = "Address")
@Table(name = "address")
@DynamicUpdate
public class Address implements Serializable
{
@Id
@ManyToOne
@JoinColumn(name = "customer_id", nullable = false)
private Customer customer;
@Id
@Column(name = "seqnumber", nullable = false)
private Integer seqnumber;
@Override public boolean equals(Object obj)
{
return obj instanceof Address
&& ((Address) obj).getCustomer().equals(this.getCustomer())
&& ((Address) obj).getSeqNumber() == this.getSeqNumber();
}
}
使用javax.persistence.EntityManager.persist创建客户+地址并使用javax.persistence.EntityManager.find检索客户已经成功。 但是,在调用javax.persistence.EntityManager.merge时,我无法使用新的/更改/删除的地址来更新客户。
// get data from REST service
// create customer entity - a customer with id 123 already exists in the db
Customer c = new Customer();
c.setId(123);
// create new address entity - no address with seqnumber 2 for customer 123 exists in db
Address a = new Address();
a.setCustomer(c); // or setCustomerId(123) when I tried unidirectional without the ManyToOne
a.setSeqNumber(2);
// add address to customer
c.getAddresses().add(a);
entityManager.merge(c);
我尝试了单向的OneToMany关系,该关系具有客户实体中的地址列表,并且仅具有地址实体中具有地址序号的客户ID。但是,当我从列表中删除一个地址并添加一个新地址时,调用merge导致插入到地址表中,并且复合键为null(尽管在合并之前已设置)。
因此,我切换到双向OneToMany / ManyToOne关系,并在Address实体中添加了Customer对象,而不是客户ID(请参见上面的类)。这意味着我不得不在Address类的equals方法中使用customer对象而不是customer-id,这导致了StackOverflowError。
有人可以给我提示如何正确建模吗?我需要对关系进行建模吗?调用合并不是正确的方法吗?
感谢您的帮助,在此先感谢您!
更新: 我终于在Hibernate论坛here上找到了答案。似乎合并功能不能(始终)保证我要寻找的行为。合并应用于“重新附加已分离的实体,而不用于获取任意临时对象”。 因此,我没有通过合并简单地通过find来获取现有实体,然后更新了所获取的现有实体的地址列表以匹配我的瞬时更新实体。