我和父母之间有一对多的关系。 以下是该关系的代码段。
@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
因为没有更新它们。
有没有人知道为什么会发生这种情况?
提前致谢!
答案 0 :(得分:1)
实际上这是设计的。在所有子项上调用PreUpdate
的原因是,在这种情况下,hibernate首先删除所有子项,然后重新插入它们。 http://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#associations-one-to-many-unidirectional中描述了此行为。
您遇到此问题,因为在这种情况下,父级拥有该关联。这意味着当保存父级时,父级和子级之间的关联将在数据库中更新。没有其他方法可以删除所有子项并重新插入它们。
有人可能会提出这样的解决方案:hibernate跟踪对集合所做的更改,只插入已添加的记录并删除已删除的条目。虽然这似乎是一个解决方案,但如果已经在数据库中更改了关联,它将无法工作。
问题的实质是当客户端调用parent.save
时,它期望在保存完成后数据库将包含与parent
集合中children
集合相关联的子项的记录{ {1}}已被调用。
如果hibernate只跟踪添加和删除并且只执行这些操作,则以下方案将导致问题。
我们假设父母已经与两个孩子联系在一起:
save
然后两个客户端同时从数据库中读取父状态。
客户1:
Parent parent = new Parent();
parent.children(asSet(child1, child2));
parent.save();
客户2:
Parent parent = dao.getParent(parentId);
第一个客户端添加一个孩子并保存:
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
。
希望这是有道理的并解释为什么冬眠会移除所有孩子并重新插入它们。
要解决您的问题,您需要使用bidirectional child3
关联,以便关联的子方管理它。