Java Hibernate合并问题与一对一映射
我在Hibernate(3.5.6最终版)中使用JPA2.0-Java Hibernate合并问题与一对一映射,java,hibernate,jpa-2.0,Java,Hibernate,Jpa 2.0,我在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 @PrimaryK
@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
}
现在,我将引用B
的实体Foo
保存到字段“a”。稍后,我想用类C
将Foo的实例更新为属性“a”,所以我所做的是-loadedFooInstance.setA(new C());
entityManager.merge(loadedFooInstance);
但我注意到的是,在分配C之前,它不会删除分配给该Foo对象的原始B对象。因此,在分配新实例之前,我需要手动删除分配给该Foo实例的A的所有引用但是我相信hibernate一定有办法处理这样的场景,我在映射中遗漏了一些东西。
我的地图有什么问题吗。。或者这种映射可以更好地实现,所以我不需要处理这种手工工作。您的OneTONE关系由A方管理,而不是由Foo方管理。因此,您需要更改A端的关系(因为hibernate只关注管理关系的一端) 另一种方法是更改管理关系的一方:
public abstract class A{
...
@OneToOne(mappedBy = "a")
private Foo foo;
...
}
public class Foo{
...
@OneToOne
@JoinColumn(name = "a_id", nullable = false)
private A a
...
}
但这也会改变你的数据库布局 此模式中的某些内容不正确。当您删除B时,您希望删除Foo,因此A是关系的拥有方。所以如果没有B的存在,Foo就不应该存在。但是你现在所做的是从Foo中删除B,因此违反了关系,因为现在没有B。你应该遵循拉尔夫的建议2。建议#1行得通,但显然富应该是拥有方。而级联也将从映射的旁边工作。您定义的关系不正确 编辑: 要将Foo中的现有B设置为C: 这几乎与拉尔夫早期的建议相似
我不想更改数据库布局。。因为我想应用删除级联。。因此,如果Foo被删除,那么A必须自动删除。在第二个选项中,不可能应用这样的删除级联,对吗?@Premraj M:对于第二个场景:您可以将cascade=CascadeType.ALL-on应用到Foo.a.-我不知道它在mappedBy方面是否有效,但我不想在Foo中保留A的Id,因此如果HQL删除了Foo,那么A应该自动删除(在DB端使用delete cascade)。。现在有这样的映射有意义吗?@Premraj M:Summary:每个hibernate关系都有两个方面:一个是维护关系的方面,另一个是“只读”的方面,每个关系都有一个存储foraign键的方面,另一个方面(由映射)。通常,关系维护端和密钥存储端是相同的。-您可以通过设置“反向”标志使非存储端变为维护端,并将存储端设置为只读(update=false,insert=false)但是我不知道级联删除从“mapped by”端到“foraign key”端都是有效的。@Premraj M:但是根据我的经验,更改维护端通常会导致问题,所以不要一直这样做,因为你并不真正需要它。并为这种关系编写一系列测试用例如果你有更多的问题,那么问一个新问题,因为所有这些都超出了这个问题的范围。不。。当我删除Foo时,我想删除与Foo相关的B或C。。这有意义吗?或者您可以提供示例来定义与此要求的关系。@Premraj M-然后您应该显式地从foo中删除A的所有关联实例,然后在新的A实例中设置foo并持久化。这是必需的,因为您不能从A端对Foo应用cascade all,否则,删除A也会删除Foo。请参见编辑。@Premraj M-旧的A instance即B从未从数据库中删除,我认为它不应该存在于数据库中。此外,还必须保存C或在foo上执行级联合并操作。
public abstract class A{
...
@OneToOne(mappedBy = "a")
private Foo foo;
...
}
public class Foo{
...
@OneToOne
@JoinColumn(name = "a_id", nullable = false)
private A a
...
}
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);