Hibernate合并问题与一对一映射

时间:2011-03-16 15:05:40

标签: java hibernate jpa-2.0

我在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必须有办法处理这样的场景,而且我在映射中遗漏了一些东西。 我的映射有什么问题吗?或者这种映射可以用更好的方式实现,所以我不需要处理这样的手工工作。

2 个答案:

答案 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);