我有一个类似下面的课程:
@Entity
@Table(name="work")
public class Work {
@Id
@Column(name="id")
private String id;
@OneToMany(orphanRemoval=true ,mappedBy="work", cascade=CascadeType.ALL , fetch=FetchType.EAGER)
private List<PersonRole> personRoleList;
}
由于我是一个Web应用程序,当我更新(来自客户端)一个personRoleList
项目并致电:
session.update(work); //`work` is in detached state
它不会更新实际添加新项目的personRoleList
项。
其他一些人也有同样的问题。 REF:
using-saveorupdate-in-hibernate-creates-new-records-instead-of-updating-existi
jpa-onetomany-not-deleting-child
我尝试了所有建议的解决方案,但它们都不适合我。
但是然后我就试过了:
session.merge(work); //replacing session.update(work)
按预期工作。!!
这是我感到困惑的地方。因为在OneToMany关系(或可能是我错过)的情况下,我无法找到行为差异的任何解释。我阅读了一些主题,以了解update()
和merge()
之间的差异并完成了文档。 REF:
what-are-the-differences-between-the-different-saving-methods-in-hibernate
differences-among-save-update-saveorupdate-merge-methods-in-session
但仍然不清楚创造这种差异的那些行为模式/逻辑/步骤是什么。
答案 0 :(得分:1)
合并尝试将当前临时对象与当前由会话管理的持久对象相关联并合并&#39;他们成为一个实体。它的用途是当你有一个分离的对象和一个附加的对象并希望解决它们。
在merge()
中,如果会话中没有托管实例,Hibernate将从数据库中读取实体。在您的示例中,这将导致Hibernate急切地加载集合(由于fetch=FetchType.EAGER
)。然后,当您的会话结束时,Hibernate将检查集合中的更改(由于cascade=CascadeType.ALL
)并将在数据库中执行相应的UPDATE。
这与update()
场景不同,因为在更新中Hibernate始终(默认情况下)假定对象是脏的并且计划更新。此更新很可能导致在您的集合中创建新元素 - Hibernate没有查看数据库以在发布UPDATE之前将集合带入会话。
我敢打赌,您可以通过设置
获得update()
所需的行为
select-before-update="true"
在您的类映射中,或者在进行更改之前使用lock
方法将对象重新附加到会话。
Java Persistence with Hibernate
的第9章项目对象在传递到之前或之后是否被修改无关紧要 更新()。这里重要的是调用update()是将分离的实例重新附加到新的Session(和持久化上下文)。过冬 始终将对象视为脏对象并调度SQL UPDATE,这将在刷新期间执行。您可以在图9.8中看到相同的工作单元。 你可能会感到惊讶,也许希望Hibernate知道你 修改了分离项目的描述(或者Hibernate应该知道你做了 不要修改任何东西)。但是,新的Session及其新的持久化背景 没有这个信息。分离对象也不包含您所做的所有修改的内部列表。 需要数据库中的UDPATE。避免这种UDPATE语句的一种方法是 使用select-before-update =&#34; true&#34;配置Item的类映射。 属性。然后,Hibernate通过执行a确定对象是否脏 SELECT语句并将对象的当前状态与当前数据进行比较 - 基础状态。