We have two JPA entities, let's call them 'C' and 'P'. These Entities have a one-to-one optional relationship based on their primary keys. That is, Entity 'P' can exist without a related Entity 'C', and vice versa.
When we try to delete a 'C' Entity, we first 'find' the Entity which loads it into the EntityManager's Persistence Context. A consequence of this is that Hibernate insists on Eager loading the associated 'P' Entity, and creates object references from each object to the other.
However, if we then 'remove' the 'C' Entity and try to 'flush', the EntityManager complains that the 'P' Entity has an unsaved transient reference to the now removed 'C' Entity. But we never asked the EntityManager to 'merge' the 'P' Entity.
What we want to know is why is the EntityManager making a decision to merge the 'P' Entity? Is there a class that we can switch on logging for to see what rational it is using to do the automatic merge? There is a possibility that our code is somehow making some sort of low-level change to the 'P' Entity, but without knowing why the EntityManager is doing the merge, we are kind of blind to what is happening.
We know that we can manually remove the object references from each object to the other and that 'fixes' the problem, but why is this necessary when we don't want to merge the 'P' Entity?
UPDATE:
So I found a way to add an Interceptor
which catches the 'onFlushDirty' event during Hibernate's dirty checking.
When our error occurs, the P
entity is not marked as dirty, so now I really don't know why Hibernate is trying to merge it.
The only thing I can think of is that the C
entity that P
entity refers to is somehow different to the C
entity that we tell the EntityManager to remove, and that's why Hibernate thinks it is an 'unsaved transient'.
We have two JPA entities, let's call them 'C' and 'P'. These Entities have a one-to-one optional relationship based on their primary keys. That is, Entity 'P' can exist without a related Entity 'C', and vice versa.
When we try to delete a 'C' Entity, we first 'find' the Entity which loads it into the EntityManager's Persistence Context. A consequence of this is that Hibernate insists on Eager loading the associated 'P' Entity, and creates object references from each object to the other.
However, if we then 'remove' the 'C' Entity and try to 'flush', the EntityManager complains that the 'P' Entity has an unsaved transient reference to the now removed 'C' Entity. But we never asked the EntityManager to 'merge' the 'P' Entity.
What we want to know is why is the EntityManager making a decision to merge the 'P' Entity? Is there a class that we can switch on logging for to see what rational it is using to do the automatic merge? There is a possibility that our code is somehow making some sort of low-level change to the 'P' Entity, but without knowing why the EntityManager is doing the merge, we are kind of blind to what is happening.
We know that we can manually remove the object references from each object to the other and that 'fixes' the problem, but why is this necessary when we don't want to merge the 'P' Entity?
UPDATE:
So I found a way to add an Interceptor
which catches the 'onFlushDirty' event during Hibernate's dirty checking.
When our error occurs, the P
entity is not marked as dirty, so now I really don't know why Hibernate is trying to merge it.
The only thing I can think of is that the C
entity that P
entity refers to is somehow different to the C
entity that we tell the EntityManager to remove, and that's why Hibernate thinks it is an 'unsaved transient'.
- If you guys dont want to get the P with C, just use lazy. Using eager will trigger P to go with C even when it null or not. – Nguyen Huu Phuc Commented Mar 18 at 2:26
- @NguyenHuuPhuc We're not loading the 'P' explicitly, the association is already LAZY, optional. Hibernate loads it automatically if the One-to-one is on the primary key. We can't stop Hibernate doing this. That's just the way Hibernate works – DuncanKinnear Commented Mar 18 at 2:56
1 Answer
Reset to default 1This behavior is due to Hibernate’s dirty checking mechanism. When you load entity C
, Hibernate eagerly loads the associated P
entity due to the bidirectional relationship. Even though P
is not explicitly merged, Hibernate detects a change in the relationship and assumes P
has been modified, triggering an implicit merge.
Set Cascade Type Explicitly
Make sure your @OneToOne
mapping does not include CascadeType.ALL
or CascadeType.MERGE
if you don’t want automatic merges:
@OneToOne(optional = true, mappedBy = "c", cascade = CascadeType.REMOVE)
private P p;
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744532429a4579227.html
评论列表(0条)