如果我有这两个实体:
@Entity class A {
@OneToOne(cascade = CascadeType.MERGE, mappedBy = "a") B b;
//getters+setters
}
@Entity class B {
@OneToOne(cascade = CascadeType.MERGE) A a;
//getters+setters
}
JPA规范保证这个吗?
A a = new A();
B b = new B();
a.setB(b);
b.setA(a);
A managedA = entityManager.merge(a);
// after commit, managedA will have a reference to a managed B which JPA implementation will link to managedA instead of original unmanaged A
Assert.assertTrue(managedA.getB().getA() == managedA);
我的理解是它可以工作(至少在最新的EclipseLink中,至少有时),但规范并不能保证这一点。
反例/规范摘录欢迎:-)
您是对的,JPA规范并不能保证这一点。实际上,在大多数情况下,merge()的语义是返回一个新实例——由实体管理器创建的托管实例,将给定对象的状态合并到该实例中——但这只是一种简化。如果它附加了您放入的对象,那么该方法实际上可能返回void(就像persist()方法一样)。我不知道为什么它被设计成那样——实际上有这种不同的语义是有点痛苦的,它花了我们一些时间来封装我们的应用程序代码中期望的行为。
合并操作的实际语义可以在3.2.7.1合并JPA规范最终版本的Detached Entity State中找到。根据您放入的对象和当前持久性上下文,它的行为会有所不同。
旁注:只要你不使用扩展的持久化上下文,一个实体在事务结束后就会分离。
还请注意,通常不应该使用==操作符比较对象,因为这实际上不是您希望的对象比较的语义(jvm标识不等于业务对象标识)