如果我有这两个实体:
@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() 方法一样)。我不知道为什么要这样设计 - 拥有这种不同的语义实际上有点麻烦,我们花了一些时间将所需的行为封装到我们的应用程序代码中。
合并操作的实际语义可以在 JPA 规范的 3.2.7.1 合并分离的实体状态 最终版本中找到。根据您放入的对象和当前的持久性上下文,它的行为确实有所不同。
旁注:只要您不使用扩展的持久性上下文,实体就会在事务结束后立即分离。
另请注意,您通常不应使用 == 运算符比较对象,因为这实际上不是您希望用于对象比较的语义(jvm 标识不等于业务对象标识)
关于java - JPA双向@OneToOne与级联合并,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15438040/