9

以下两个声明到底有什么区别

B是拥有方

@Entity
class A {
   @Id int id;

   @OneToOne
   B b;
}

@Entity
class B {
   @Id int id;

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

A是拥有方

@Entity
class A {
   @Id int id;

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

@Entity
class B {
   @Id int id;

   @OneToOne
   A a;
}

在“普通 SQL”中考虑这一点,我认为这与拥有两个表相同,每个表都有另一个表的外键。我不明白的是,指定哪个实体是拥有方的效果是什么,即使用“mappedBy”属性。这实际上实现了什么,因为我不相信普通 SQL 中存在等价物。

4

4 回答 4

14

JPA 2.0 规范第2.9 节写道:

关系可以是双向的或单向的。双向关系既有拥有方,也有反向(非拥有)方。单向关系只有拥有方。关系的拥有方决定数据库中关系的更新,如 3.2.4 节所述。

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

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

第 3.2.4 节的相关部分是:

持久实体的状态在事务提交时同步到数据库。这种同步涉及将任何对持久实体及其关系的更新写入数据库,如上所述。

托管实体之间的双向关系将基于关系拥有方持有的引用进行持久化。开发人员有责任在内存引用发生变化时保持拥有侧的内存引用和反向侧的引用保持一致。在单向一对一和一对多关系的情况下,开发人员有责任确保遵守关系的语义。

尤其重要的是要确保对关系反向方的更改会导致拥有方进行适当的更新,以确保更改同步到数据库时不会丢失。

于 2012-06-10T12:59:45.503 回答
6

正如其他人指出的那样,您在示例中哪一方是拥有方是错误的。对于拥有方,我们的意思是从 OO 角度拥有关系,实际上,如果使用 rdbm 作为持久性提供程序,通常最终会与在 db 中生成或将生成的关系相反。

在正常情况下,OO 模型非常清楚哪些方是拥有方。例如,订单有 OrderLines。如果我们删除一个订单,所有的订单行都应该被删除。如果我们删除 OrderLine,则 Order 可能仍然具有存在权。因此,订单是拥有方。

对于一个更具体和优秀的例子,关于哪一方是拥有方的影响,我参考@JB Nizet 的回答。

根据JPA 2.0 规范的第 2.9 节:

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

但在同一部分中,我们也有:

此外,本规范还要求支持以下可选映射策略:[..] 单向和双向一对一关系、双向多对一/一对多关系和单向多向关系的映射通过连接表映射的一对一关系。

在同一部分继续往下一点:

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

要阅读一些关于解决该场景的一些策略,请参阅:一个几乎很好的解释

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

于 2012-06-10T13:05:18.233 回答
5

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

在第二个例子B中是拥有方。B有两列,id并且a_id. A将有一列,id.

这就是区别:-)

于 2012-06-10T12:25:44.717 回答
5

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

这意味着如果您在数据库中有一个 A 和一个 B,并且您这样做了

A a = em.find(A.class, aId);
B b = em.find(B.class, bId);
a.setB(b);

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

但如果你这样做

A a = em.find(A.class, aId);
B b = em.find(B.class, bId);
b.setA(a);

数据库中什么都不会改变,因为您修改了反面并忘记修改拥有方。

于 2012-06-10T12:41:01.867 回答