ORM映射中的“拥有方”是什么?


128

拥有方到底是什么意思?一些映射示例(一对多,一对一,多对一)的解释是什么?

以下文本摘自Java EE 6文档中@OneToOne的描述。您可以在其中看到概念拥有方面

定义与具有一对一多重性的另一个实体的单值关联。通常不必显式指定关联的目标实体,因为通常可以从被引用对象的类型中推断出该目标实体。如果关系是双向的,则非拥有方必须使用OneToOne批注中的mappingBy元素来指定拥有方的关系字段或属性。



5
我迷路了,直到我读到这样的:javacodegeeks.com/2013/04/...
darga33

2
具有外键列的数据库表被视为拥有方。因此,表示该数据库表的业务实体是该关系的Owner(拥有方)。并非必需,但大多数情况下,拥有方将具有@JoinColumn批注。
暗黑破坏神

Answers:


202

为什么拥有一方的概念是必要的:

双向关系拥有一方的想法来自这样一个事实,即在关系数据库中没有像对象一样的双向关系。在数据库中,我们只有单向关系-外键。

“拥有方”这个名字的原因是什么?

Hibernate跟踪的关系的拥有方是拥有数据库中外键的关系的一方。

拥有权概念解决的问题是什么?

以两个声明拥有方的映射实体为例:

@Entity
@Table(name="PERSONS")
public class Person {
    @OneToMany
    private List<IdDocument>  idDocuments;
}

@Entity
@Table(name="ID_DOCUMENTS")
public class IdDocument {
    @ManyToOne
    private Person person;
}

从OO的角度来看,此映射不是定义一个双向关系,而是定义两个单独的单向关系。

映射不仅会创建表PERSONSID_DOCUMENTS,还将创建第三个关联表PERSONS_ID_DOCUMENTS

CREATE TABLE PERSONS_ID_DOCUMENTS
(
  persons_id bigint NOT NULL,
  id_documents_id bigint NOT NULL,
  CONSTRAINT fk_persons FOREIGN KEY (persons_id) REFERENCES persons (id),
  CONSTRAINT fk_docs FOREIGN KEY (id_documents_id) REFERENCES id_documents (id),
  CONSTRAINT pk UNIQUE (id_documents_id)
)

注意主键pkID_DOCUMENTS唯一的。在这种情况下,Hibernate会独立跟踪关系的两端:如果将文档添加到关系中Person.idDocuments,它将在关联表中插入一条记录PERSON_ID_DOCUMENTS

另一方面,如果调用idDocument.setPerson(person),则会在table上更改外键person_id ID_DOCUMENTS。Hibernate正在数据库上创建两个单向(外键)关系,以实现一个双向对象关系。

拥有方的概念如何解决问题:

很多时候,我们要的是上表只是一个外键ID_DOCUMENTSPERSONS和额外的关联表。

为了解决这个问题,我们需要配置Hibernate以停止跟踪对Relation的修改Person.idDocuments。Hibernate应该只跟踪关系的另一IdDocument.person,为此,我们添加了mappingBy

@OneToMany(mappedBy="person")
private List<IdDocument>  idDocuments;

这是什么意思mappingBy?

这意味着类似:“在该关系的这一侧的修改已经 关系IdDocument.person的另一侧进行了映射,因此无需在额外的表中单独跟踪它。”

是否有任何GOTCHA,后果?

使用的mappedBy,如果我们只调用person.getDocuments().add(document),外键ID_DOCUMENTS被链接到新的文件,因为这不是关系的所属/跟踪的一面!

要将文档链接到新人员,您需要显式调用document.setPerson(person),因为这是该关系的所有权

当使用maptedBy时,开发人员有责任知道什么是拥有方,并更新关系的正确方,以便触发数据库中新关系的持久性。


17
我发现最好的答案解释了主义“ mappedBy” +“ inversedBy”。
Kurt Zhong

1
感谢您指定映射以及概念背后的原因。
Mohnish

1
我不知道事情是否已经改变,但是在Hibernate 5.0.9.Final上,如果我“仅调用person.getDocuments().add(document)”,则hibernate将更新外键ID_DOCUMENTS
K.Nicholas '16

1
@Karl Nicholas,您好,我们同意,@OneToMany注释的层叠属性可以设置为PERSIST,在这种情况下,休眠将所有链接的实体保存到DB。有人可以澄清一下吗?为什么作者说休眠状态不会跟踪非拥有方的更改,但实际上休眠状态会执行跟踪?
Oleksandr Papchenko

3
级联告诉提供者保存子实体,即使父实体不拥有它们,也可以有效地修改规则。如果您拥有(或拥有)mappedBy = child.field并且没有级联,那么列表的子项将不会被保存。另外,如果您没有mapBy并且没有级联,那么父级拥有该关系,并且如果将新子级放入列表中然后保存父级,它将抛出异常,因为新的子级ID无法使用保存在联接表中。希望能澄清一些事情... :)
K.Nicholas 17-10-23

142

您可以想象拥有方是引用另一方的实体。在您的摘录中,您具有一对一的关系。由于它是对称关系,因此如果对象A与对象B有关,那么最终将得出结论,反之亦然。

这意味着将对对象B的引用保存到对象A中,并将对对象A的引用保存到对象B中是多余的:这就是为什么您选择哪个对象“拥有”另一个引用该对象的对象。

建立一对多关系后,与“许多”部分相关的对象将是拥有方,否则,您将必须存储从单个对象到多个对象的许多引用。为了避免这种情况,第二类中的每个对象都将有一个指向它们所引用的单个对象的指针(因此它们是拥有者)。

对于多对多关系,由于无论如何您将需要一个单独的映射表,因此不会有任何拥有的一方。

总之,拥有方是具有相互参照的实体。


6
感谢您的澄清。
只是一个学习者,2010年

2
也许会因为我对“ mappedBy”和“ owning side”这两个名称的原因而得到我的回答,如果我们不定义拥有方GOTCHAs,该怎么办,希望它会有所帮助
Angular University

5
好吧,我猜答案基本上是正确的。但是至少对于Hibernate而言,即使多对多关系也有自己的一面。例如,这对更新行为具有影响。必须在本教程的第4(“更新Hibernate的模型类”)的密切关注:viralpatel.net/blogs/...
Pfiver

11
这个答案使人迷惑不解。在双向关系中,两个Entity对象之间都具有引用关系时,说“您可以想象拥有方是具有对另一个引用关系的实体”有什么好处?同样,“对于多对多关系,因为无论如何您都将需要一个单独的映射表,因此不会有任何拥有的一面”,这完全是不正确的:@ManyToMany关系也具有拥有的一面。同样,@OneToMany关系可以使用联接表,而您仍然必须指定拥有方。
DavidS

5
基本上,这是一个可爱的,感觉很好的答案,但有很多争议,因为它比事实更容易理解。
DavidS
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.