在向父对象添加新的子对象时,对所有子对象调用 JPA @PreUpdate



我在父母和孩子之间有一对多的关系。 下面是关系的代码片段。

@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时,它期望在保存完成后数据库将包含与调用savechildren集合中的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();

目前为止,一切都好。但是第二个客户端仍然具有只有child1child2的父客户端版本。例如,如果该客户端删除child1并保存:

parent.children().remove(child1);
parent.save();

它希望父项现在只包含child2(因为这是保存时children集合包含的内容(。但是,如果我们使用跟踪实现并且此类删除仅出现以下问题:

DELETE FROM child where parent_id = <parent_id> and id = <child1_id>

那么仍然会有两条记录与该父级相关联 -child2child3.

希望这是有道理的,并解释了为什么休眠会删除所有子项并重新插入它们。

若要解决您的问题,需要使用双向OneToMany关联,以便关联的子端对其进行管理。

最新更新