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

问题描述:

我使用JPA(特别是Hibernate)映射了两个实体。这些实体有一个一对多的关系(我已经简化了演示):尝试在“one”实体上设置“many”时奇怪的JPA一对多行为

@Entity 
public class A { 

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

@Entity 
public Class B { 

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

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

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”属性有什么可能的影响?

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

OneToMany with mappedBy是一个反面,因此当确定冲突/事务提交时关联的状态时,JPA impl不会查看此边。它只查看A.getB(),它是空的,所以JPA的关联为空。

OneToMany没有mappedBy,所以这成为拥有方,只支持自JPA 2.0以来,但我认为Hibernate支持自年龄。这就是为什么你的例子工作,如果你从OneToMany中移除mappedBy。在这种情况下,OneToMany成为拥有者的一方,因此实施“看着”这一方来决定要坚持什么。 这并不会改变您的内存关联仍然不完整的事实。你应该设置双方。

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

+0

感谢您的详细解答。 没有“mappedBy”,如果我改变了“many”方(A),他也坚持数据,所以我想它看起来都在(或者只是Hibernate?)。 毫无疑问,你应该管理你身边的关系(在记忆中),但有时你只想保持“一边”而不关心它的“许多”实体是否在内存中正确设置(引用他)。 – 2010-06-15 12:26:54