我在父母和孩子之间有一对多的关系。 下面是关系的代码片段。
@Entity
@Table(name = "Parent")
public class Parent{
@OneToMany(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
@Fetch(FetchMode.SELECT)
@JoinColumn(name = "parentId",referencedColumnName="parentId")
private Set<Child> child = new HashSet<>();
}
此外,在尝试保存和更新对象之前,我正在使用@PreUpdate
和@PrePersist
对实体执行一些审核操作。
@PrePresist
看起来工作得很好。在我尝试在数据存储中保留一个新对象之前调用它,如文档中所述。
我在使用@PreUpdate
时遇到问题。如果父母有多个孩子,并且当我们尝试向其添加另一个孩子时entityManager.merge(parent)
. 当我们插入新的子记录时,@PrePresist
被正确调用,但它也会为父对象中已经存在的所有子对象调用@PreUpdate
注释方法,尽管任何子对象都没有更改。它不应该为所有孩子调用PreUpdate
,因为他们没有更新任何内容。
有没有人知道为什么会发生这种情况?
提前感谢!
这实际上是设计使然。对所有子项调用PreUpdate
的原因是,在这种情况下,休眠首先删除所有子项,然后重新插入它们。此行为在 http://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#associations-one-to-many-unidirectional 中进行了描述。
您有此问题,因为在这种情况下,父级拥有关联。这意味着当父项被保存时,父项和子项之间的关联将在数据库中更新。除了删除所有子项并重新插入它们之外,没有办法做到这一点。
有人可能会提出一种解决方案,其中休眠跟踪对集合所做的更改,并且只插入已添加的记录并删除已删除的条目。虽然这似乎是一个解决方案,但如果数据库中的关联已经更改,它将不起作用。
问题的本质是,当客户端调用parent.save
时,它期望在保存完成后数据库将包含与调用save
时children
集合中的parent
关联的子项的记录。
如果休眠仅跟踪添加和删除并仅执行这些操作,则以下情况将导致问题。
假设父级已经与两个孩子相关联:
Parent parent = new Parent();
parent.children(asSet(child1, child2));
parent.save();
然后,两个客户端同时从数据库中读取父状态。
客户端 1:
Parent parent = dao.getParent(parentId);
客户端 2:
Parent parent = dao.getParent(parentId);
第一个客户端添加一个子项并保存:
parent.children().add(child3);
parent.save();
目前为止,一切都好。但是第二个客户端仍然具有只有child1
和child2
的父客户端版本。例如,如果该客户端删除child1
并保存:
parent.children().remove(child1);
parent.save();
它希望父项现在只包含child2
(因为这是保存时children
集合包含的内容(。但是,如果我们使用跟踪实现并且此类删除仅出现以下问题:
DELETE FROM child where parent_id = <parent_id> and id = <child1_id>
那么仍然会有两条记录与该父级相关联 -child2
和child3
.
希望这是有道理的,并解释了为什么休眠会删除所有子项并重新插入它们。
若要解决您的问题,需要使用双向OneToMany
关联,以便关联的子端对其进行管理。