尝试在“一个”实体上设置“多个”时,奇怪的JPA一对多行为

时间:2010-06-15 10:50:03

标签: hibernate jpa entity-relationship

我使用JPA(特别是Hibernate)映射了两个实体。这些实体有一对多的关系(我已经简化了演示):

@Entity
public class A {

    @ManyToOne
    public B getB() { return b; }
}

@Entity
public Class B {

    @OneToMany(mappedBy="b")
    public Set<A> getAs() { return as; }
}

现在,我试图通过使用关系的单侧/非所有者侧的setter(即引用的表)来创建这些实体的两个实例之间的关系:

em.getTransaction().begin();

A a = new A();
B b = new B();
Set<A> as = new HashSet<A>();
as.add(a);
b.setAs(as);

em.persist(a);
em.persist(b);
em.getTransaction().commit();

但是,关系不会持久保存到DB(为实体A创建的行不引用为实体B创建的行)。为什么会这样?我希望它可以工作。

此外,如果我从@OneToMany注释中删除“mappedBy”属性,工作。再次 - 为什么会这样?以及删除“mappedBy”属性可能产生的影响是什么?

1 个答案:

答案 0 :(得分:5)

在双向关联中,JPA规范被定义为当实现仅想查看关联的当前“状态”以确定需要持久化的内容并且每个双向关联都具有时,实现仅查看关联的拥有方。拥有和反面。这可以避免歧义(即,如果关联的两边不一致,该什么是持久的?)以及为JPA实现者提供优化和更简单实现的机会。请注意,这通常不是问题,因为您应该正确维护双向关联,而不是JPA。如果您始终在应用程序中正确维护双向关联(更新双方并保持一致),则没有问题。

具有mappedBy的OneToMany是反面,因此在确定刷新/事务提交时的关联状态时,JPA impl不会查看此方。它只查看A.getB()并且它为null,因此JPA的关联为空。

没有mappedBy的OneToMany,因此它成为拥有方,仅从JPA 2.0开始支持,但我认为Hibernate支持它已经很久了。这就是为什么你的示例工作如果你从OneToMany中删除mappedBy。在这种情况下,OneToMany成为拥有者,因此实现“看着”这一侧以确定要保留的内容。 这并不会改变您的内存中关联仍然不完整的事实。你应该设置双方。

更新:当你从任何一方离开mappedBy时,我不知道Hibernate究竟做了什么,但我认为这可能会导致SQL不太理想。另请参阅:http://simoes.org/docs/hibernate-2.1/155.html,特别是关于“inverse =”false“”的部分。 “inverse”是JPA“mappedBy”的原生Hibernate术语。也就是说,Hibernate映射中的inverse =“true”与在JPA映射中使用mappedBy =“other”相同,都将此方标记为在确定关联更新时被忽略的反面。