JPA - 使用mappedBy属性来定义拥有实体的区别

zig*_*ggy 8 java persistence hibernate jpa jpql

以下两个声明的区别究竟是什么?

B是拥有方

@Entity
class A {
   @Id int id;

   @OneToOne
   B b;
}

@Entity
class B {
   @Id int id;

   @OneToOne(mappedBy="b")
   A a;
}
Run Code Online (Sandbox Code Playgroud)

A是拥有方

@Entity
class A {
   @Id int id;

   @OneToOne(mappedBy="a")
   B b;
}

@Entity
class B {
   @Id int id;

   @OneToOne
   A a;
}
Run Code Online (Sandbox Code Playgroud)

在"普通SQL"中考虑这一点,我认为它与两个表各有另一个表的外键相同.我不明白的是,指定哪个实体是拥有方的效果是什么,即使用'mappedBy'属性.这实际上实现了什么,因为我不相信在普通的SQL中有相同的东西.

mer*_*ike 13

JPA 2.0规范,第2.9节,写:

关系可以是双向的或单向的.双向关系具有拥有方和反向(非拥有方).单向关系只有一个拥有方.关系的拥有方确定数据库中关系的更新,如3.2.4节所述.

以下规则适用于双向关系:

  • 的双向关系中的反向端必须通过使用的是指其持有端mappedBy 的的元素 OneToOne, OneToManyManyToMany 注释.的mappedBy元件指定在作为关系的所有者该实体的属性或字段.
  • 一对多/多对一双向关系的许多方面必须是拥有方,因此mappedBy无法在ManyToOne注释上指定元素.
  • 对于一对一的双向关系,拥有方对应于包含相应外键的一侧.
  • 对于多对多双向关系,任何一方都可能是拥有方.

3.2.4节的相关部分是:

持久实体的状态在事务提交时与数据库同步.此同步涉及向数据库写入对上面指定的持久性实体及其关系的任何更新.

管理实体之间的双向关系将基于关系所属方所持有的引用而持久化.开发人员有责任保持内存引用保持在拥有方,而保持在反方保持的内容引用在更改时保持一致.在单向一对一和一对多关系的情况下,开发人员有责任确保遵守关系的语义.

特别重要的是要确保对关系的反面的更改导致在所有方面进行适当的更新,以确保在它们与数据库同步时不会丢失更改.


JB *_*zet 7

拥有方是 JPA 认为知道关联是否存在的一方。假设您使用第一个示例。拥有方是没有mappedBy 属性的一方。因此,拥有方是 A,而不是 B。

这意味着如果数据库中有 A 和 B,并且您确实

A a = em.find(A.class, aId);
B b = em.find(B.class, bId);
a.setB(b);
Run Code Online (Sandbox Code Playgroud)

JPA将保存关联(即将B的ID存储在表A的连接列中)。

但如果你这样做

A a = em.find(A.class, aId);
B b = em.find(B.class, bId);
b.setA(a);
Run Code Online (Sandbox Code Playgroud)

数据库中不会发生任何更改,因为您修改了反面并忘记修改了拥有面。


sie*_*z0r 5

在第一个示例中,该A表将有 2 列,id并且b_idB表将有一个列,id。这使得A拥有方。

第二个例子B是拥有方。B有两列,ida_idA将有一列,id.

这就是区别:-)


ese*_*sej 5

正如其他人所指出的那样,你的例子中哪一方是你自己的一方是错的.随着拥有我们的意思是拥有一个面向对象perspecitve的关系方面,在很多时候最终被它是如何或将在数据库中,如果一个使用RDBM作为持久性提供者产生相反的做法.

在正常情况下,OO模型清楚地表明哪一方是拥有方.例如,Order有OrderLines.如果我们删除订单,则应删除所有订单行.如果我们删除OrderLine,订单可能仍然有权存在.因此,订单是拥有方.

对于一个更具体和更好的例子,关于哪一方是拥有方的影响,我指的是@JB Nizet的回答.

根据JPA 2.0规范第2.9节:

对于一对一的双向关系,拥有方对应于包含相应外键的一侧.

但在同一部分,我们还有:

此外,该规范还要求支持以下备选映射策略:[...]单向和双向一对一关系的映射,双向多对一/一对多关系,以及单向多个 - 通过连接表映射实现一对一的关系.

在同一部分中继续下去:

可以指定附加的映射注释(例如,列和表映射注释)来覆盖或进一步细化第2.10节中描述的默认映射和映射策略.一些实现利用它来允许双向OneToOne的FK在目标表中.

要阅读一些解决这种情况的策略,请参阅:一个几乎很好的解释

我没有检查,但我希望并相信2.1将删除第一个引用.由于实际的数据库结构应该尽可能地限制我们如何将数据建模为实体.