我有一个问题,我驱逐一个实体,但对其进行的更改仍将更改数据库。这是我DAO中方法的一部分。
@Entity
public class Profile {
@Id
@GeneratedValue
private Long id;
@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "PROFILE_ID")
@LazyCollection(LazyCollectionOption.FALSE)
private List<Avatar> avatars;
...
}
在DAO方法中:
Profile profile = getProfile(...);
// Clear from hibernate
currentSession.evict(profile);
profile.setId(null);
for (Avatar a : profile.getAvatars()) {
currentSession.evict(a);
a.setId(null);
}
currentSession.save(profile); // save a copy of Profile (not update)
之前:
PUBLIC.PROFILE
ID, DOMAIN, STATUS
1, "test", "MEMBER"
PUBLIC.AVATAR
ID, NAME, PROFILE_ID
1, "main", 1
方法
之后PUBLIC.PROFILE
ID, DOMAIN, STATUS
1, "test", "MEMBER"
2, "test", "MEMBER"
PUBLIC.AVATAR
ID, NAME, PROFILE_ID
1, "main", null
2, "main", 2
正如您所看到的,AVATAR中的原始行现在具有空外键。
为什么呢?这是在使用Unitils和Spring 和的单元/集成测试中发生的,这可能会影响Hibernate DAO的工作方式。
它全部存储在内存H2数据库中。
添加一行后
profile.setAvatars(new ArrayList<>(profile.getAvatars());
它有效......
所以我猜问题是Hibernate对List
的实现,但是这怎么会影响行为?
答案 0 :(得分:0)
编辑:由于@LazyCollection(LazyCollectionOption.FALSE)
我可以重现和修复,但我无法理解引擎盖下究竟发生了什么......
首先发生了什么(在调试器下窥探):
由于avatars
集合非常渴望,profile.getAvatars()
已完全填充且是Hibernate集合(在我自己的测试中,它是PersistentBag
)
当profile
被驱逐时,其所有化身也被驱逐(至少使用Hibernate 4.1.9 Final)。
在currentSession.save(profile)
上,所有内容都非常棒,我们会插入一个新的Profile
以及一个新的Avatar
。但是在遵循事务提交时,Hibernate决定执行着名的update Avatar set profile_id = null where profile_id = 1;
: - (
接下来修复:
我认为Hibernate很惊讶地发现一个新实体已经有一个PersistentBag
来携带一个集合。所以我创建了一个简单的ArrayList
,附加了当前Avatars
,并将其放入profile
:
List<Avatar> avatars = new ArrayList<Avatar>();
for (Avatar a : profile.getAvatars()) {
currentSession.evict(a); // in fact useless but harmless
a.setId(null);
avatars.add(a);
}
profile.setAvatars(avatars);
而且......一切都很好,Hibernate不再发出令人讨厌的更新!
所以原因似乎是新实体中的PersistentBag
,但我无法想象Hibernate内部实际发生了什么。