最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

java - Hibernate Entity Manager behaviour logging - Stack Overflow

programmeradmin3浏览0评论

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'.

Share Improve this question edited Mar 20 at 2:12 DuncanKinnear asked Mar 17 at 22:19 DuncanKinnearDuncanKinnear 4,6532 gold badges38 silver badges67 bronze badges 2
  • 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
Add a comment  | 

1 Answer 1

Reset to default 1

This 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;
发布评论

评论列表(0)

  1. 暂无评论