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

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

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

将单值关联定义为 一对一的另一个实体 多样性。这是不正常的 指定相关的 目标实体,因为它可以 通常是从... 的类型推断出来的 被引用的对象。如果 关系是双向的 非所有方 必须使用 mappedBy OneToOne 注释的元素添加到 指定关系字段或 拥有方的财产。

52895 次浏览

可以想象,拥有一方是具有对另一个 拥有一方的引用的实体。在你的节选中,你们是一对一的关系。因为它是 对称的关系,所以如果对象 A 与对象 B 相关,那么反之亦然。

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

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

对于多对多关系,因为无论如何都需要一个单独的映射表,所以不会有任何所有方。

总而言之,拥有一方是具有对另一个 拥有一方的引用的实体。

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

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

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

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;
}

从面向对象的角度来看,这种映射定义的不是一个双向关系,而是 独立的单向关系。

这个映射不仅会创建表 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)
)

注意,只有 ID_DOCUMENTS上的主键 pk。在这种情况下,Hibernate 独立地跟踪关系的两端: 如果向关系 Person.idDocuments添加一个文档,它将在关联表 PERSON_ID_DOCUMENTS中插入一条记录。

另一方面,如果我们调用 idDocument.setPerson(person),我们将更改表 ID_DOCUMENTS上的外键 person _ id。Hibernate 在数据库上创建 单向(外键)关系,以实现 双向对象关系。

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

很多时候,我们想要的只是表 ID_DOCUMENTS上面向 PERSONS的一个外键,而不是额外的关联表。

为了解决这个问题,我们需要配置 Hibernate 来停止跟踪关系 Person.idDocuments上的修改。Hibernate 应该只跟踪关系 IdDocument.person其他端,为此我们添加 地图:

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

地图是什么意思?

这意味着: “关系的这一侧的修改已经 < strong > Maps By 关系 IdDocument.person 的另一端,因此不需要 分开放在另一张桌子上。”

有什么后果吗?

使用 地图,如果我们只调用 person.getDocuments().add(document)ID_DOCUMENTS中的外键将 没有链接到新的文档,因为这不是关系的拥有/跟踪一侧!

要将文档链接到新用户,需要显式调用 document.setPerson(person),因为它是关系的 拥有方

在使用 地图时,开发人员有责任知道所属方是什么,并更新关系的正确一侧,以触发数据库中新关系的持久性。

双向关系必须遵循以下规则。

双向关系的反向端必须通过使用@OneToOne、@OneTomany 或@ManyTomany 注释的 mappedBy 元素来引用其所属端。MappedBy 元素指定作为关系所有者的实体中的属性或字段。

多对一双向关系的多边不能定义 mappedBy 元素

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

对于多对多双向关系,任何一方都可能是拥有方。

这很有帮助,我支持这个讨论

特别是我正在寻找以下用例在医院管理系统。 病人-> 病人病史 1.病人不依赖于病人的病史,即只有在第一次病人访问医院时,他的病史必须加上。 2.在随后的访问中,历史记录被添加到历史表中,但是需要一个对 Patientid 的引用。因此,这里的外键是 PatientHistory 表中的外键,所属方是 PatientHistory

因此,这种关系必须建模为患者实体中的“患者”映射的双向 OneTomany。每个实体相互引用。

我将简要地解释一下这个问题。“ Owning”表示本身携带外键列。换句话说,它拥有这种关系。许多人误解了“拥有”这个词。他们认为所有者党是主要党派。但是当我们查看它时,带有外键列的表是链接端。例如: 让我们考虑 Person 和 Address 以及它们之间的关系 OneToOne

@Data
@Entity
public class Person {


@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;


private String name;


@OneToOne
@JoinColumn(name = "adress_id")
private Adress adress;
}


@Data
@Entity
public class Adress {


@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;


@OneToOne(mappedBy = "adress")
private Person person;


}

在这种情况下,Person 有 address _ id fk 列,它链接了主键列的 Address。

一般来说,你可能会想,为什么我需要拥有的一面?要理解这一点,您需要了解数据库规则。例如,假设您不希望在一个表中使用拥有方和所有数据存储,这意味着实现了一个糟糕的数据库实践。因此,我假设您现在理解了每个实体应该在其自己的表中存储自己的数据。现在他们要求您在视图部分显示 Person 和他的 Address。如果没有拥有方,你会怎么做?您可能必须为每个实体创建两个查询,对吗?在这里,您也做了一个糟糕的 DML。您可以使用 JOIN编写1个查询,而不是编写2个查询。JOIN 与我们定义的拥有方的工作,如果没有它们,我们就不能从另一个表中选择属于一个表的数据。ORM 还为您提供了一种更舒适的方法,即通过实体使用基本的 Java 代码而不使用数据库。就是这样。