I have a problem where I evict an entity, but changes made to it will still change the database. This is part of the method in my 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;
...
}
In a DAO method:
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)
before:
PUBLIC.PROFILE
ID, DOMAIN, STATUS
1, "test", "MEMBER"
PUBLIC.AVATAR
ID, NAME, PROFILE_ID
1, "main", 1
after method
PUBLIC.PROFILE
ID, DOMAIN, STATUS
1, "test", "MEMBER"
2, "test", "MEMBER"
PUBLIC.AVATAR
ID, NAME, PROFILE_ID
1, "main", null
2, "main", 2
So as you can see, the original row in AVATAR has now a null foreign key.
Why? This is happening in a unit / integration test using Unitils and Spring and this might influence how the Hibernate DAO works, maybe.
It's all in a in-memory H2 database..
After adding a line
profile.setAvatars(new ArrayList<>(profile.getAvatars());
it works ...
So I guess the problem was Hibernate's implementation of List, but how could that affect the behavior??
EDIT : First answer was stupid because of
@LazyCollection(LazyCollectionOption.FALSE)I could reproduce and fix but I cannot understand what actually happens under the hood ...
First what happens (spyed under debugger):
As
avatarscollection is eager,profile.getAvatars()is fully populated and is a Hibernate collection (in my own tests, it is aPersistentBag)When
profileis evicted, all its avatars are also evicted (at least with Hibernate 4.1.9 Final).On
currentSession.save(profile)all is marvelous, a newProfileis inserted and also a newAvatar. But on following transaction commit, Hibernate decides to do the famousupdate Avatar set profile_id = null where profile_id = 1;:-(Next the fix :
I supposed that Hibernate is surprised to find a new entity already having a
PersistentBagto carry a collection. So I created a simpleArrayList, appended currentAvatarsto it, and put it intoprofile:And ... all is fine, Hibernate no longer emits the offending update !
So the cause seems to be a
PersistentBagin a new entity, but i cannot imagine what actually happens in Hibernate internals.