我在Hibernate(最终的3.5.6)和JPA 2.0中使用InheritanceType.JOINED映射了一个类层次结构 -
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class A{
private Long id;
@OneToOne
@JoinColumn(name = "foo_id", nullable = false)
private Foo foo;
...
}
@Entity
@PrimaryKeyJoinColumn(name = "B_ID")
public class B{
...
}
@Entity
@PrimaryKeyJoinColumn(name = "C_ID")
public class C{
...
}
Foo
实体是 -
@Entity
public class Foo{
@Id
private Long id;
@OneToOne(cascade = CascadeType.ALL, mappedBy = "foo")
private A a
// getters / setters omitted
}
现在我将实体Foo
保存为B
到字段'a'。稍后我想将类C
的引用更新为Foo的实例到属性'a',所以我做的是 -
loadedFooInstance.setA(new C());
entityManager.merge(loadedFooInstance);
但我注意到 - 它不会删除在分配C之前分配给该Foo对象的原始B对象。因此,我需要删除分配给该Foo实例的所有A引用 之前分配新的。
但是我相信hibernate必须有办法处理这样的场景,而且我在映射中遗漏了一些东西。
我的映射有什么问题吗?或者这种映射可以用更好的方式实现,所以我不需要处理这样的手工工作。
答案 0 :(得分:0)
您的OneToOne关系船由A方管理,而不是由Foo方管理。所以你需要改变A方的关系(因为hibernate会关注管理关系的那一方)
A old = loadedFooInstance.getA();
oldA.setFoo(null);
C c = new C();
c.setFoo(loadedFooInstance);
/*and it is good practic to update foo too*/
loadedFooInstance.setA(c);
另一种方式是改变管理关系的一面:
public abstract class A{
...
@OneToOne(mappedBy = "a")
private Foo foo;
...
}
public class Foo{
...
@OneToOne
@JoinColumn(name = "a_id", nullable = false)
private A a
...
}
但这也会改变你的数据库布局!
答案 1 :(得分:0)
此架构中的某些内容不正确。删除B时,要删除Foo,因此A是关系的拥有方。因此,如果不存在B,Foo就不应该存在。但你现在正在做的是从Foo中删除B,因此违反了关系,因为现在没有B.你应该遵循Ralph的建议#2。建议#1可以正常工作,但显然Foo应该是拥有的一方。级联也可以从映射旁边工作。您定义的关系不正确。
编辑:
为了将Foo中的现有B设置为C: 这与拉尔夫的早期建议#1
几乎相似Foo foo = entityManager.find(Foo.class, id);
B b = foo.getA();
entityManager.remove(b); //Explicitly remove or B still remains in database as B is the owning side
C c = new C();
c.setFoo(foo);
entityManager.persist(c); //c is the owning side, hence save c and not foo
entityManager.refresh(foo);