有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

一对一映射的java Hibernate合并问题

我有一个用InheritanceType映射的类层次结构。加入Hibernate(最终版本3.5.6)和JPA2.0-

@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) 个答案

  1. # 1 楼答案

    此架构中的某些内容不正确。当您删除B时,您希望删除Foo,因此A是关系的拥有方。所以如果没有B的存在,Foo就不应该存在。但是你现在所做的是从Foo中删除B,因此违反了关系,因为现在没有B。你应该遵循拉尔夫的建议2。建议#1行得通,但显然富应该是拥有方。而级联也将从映射的旁边工作。您定义的关系不正确

    编辑:

    要将Foo中的现有B设置为C: 这几乎与拉尔夫早期的建议相似

    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);
    
  2. # 2 楼答案

    您的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
        ...
     }
    

    但这也会改变你的数据库布局