[英]What is the "owning side" in an ORM mapping?
拥有方究竟是什么意思? 一些映射示例(一对多、一对一、多对一)的解释是什么?
以下文本摘自 Java EE 6 文档中对@OneToOne的描述。 您可以在其中看到概念拥有的一面。
定义与另一个具有一对一多重性的实体的单值关联。 通常不需要明确指定关联的目标实体,因为它通常可以从被引用的对象的类型中推断出来。 如果关系是双向的,非拥有方必须使用 OneToOne 注解的 mappedBy 元素来指定拥有方的关系字段或属性。
为什么拥有方的概念是必要的:
双向关系拥有方的想法来自这样一个事实,即在关系数据库中没有像对象那样的双向关系。 在数据库中,我们只有单向关系——外键。
名称为“拥有方”的原因是什么?
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;
}
从面向对象的角度来看,该映射定义的不是一个双向关系,而是两个单独的单向关系。
映射将创建不仅表PERSONS
和ID_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
上的外键ID_DOCUMENTS
。 Hibernate 正在数据库上创建两个单向(外键)关系,以实现一个双向对象关系。
拥有方的概念如何解决问题:
很多时候,我们要的是只对表的外键ID_DOCUMENTS
朝PERSONS
和额外的关联表。
为了解决这个问题,我们需要配置 Hibernate 以停止跟踪关系Person.idDocuments
上的修改。 Hibernate 应该只跟踪关系IdDocument.person
的另一侧, IdDocument.person
我们添加了mappingBy :
@OneToMany(mappedBy="person")
private List<IdDocument> idDocuments;
是什么意思 mappingBy ?
这意味着类似于:“关系这一侧的修改已经被关系 IdDocument.person 的另一侧映射,因此无需在额外的表中单独跟踪它。”
是否有任何 GOTCHA,后果?
使用mappingBy ,如果我们只调用person.getDocuments().add(document)
, ID_DOCUMENTS
的外键将不会链接到新文档,因为这不是关系的拥有 /tracked 一侧!
要将文档链接到新人,您需要显式调用document.setPerson(person)
,因为这是关系的拥有方。
在使用mappingBy 时,开发人员有责任知道拥有方是什么,并更新关系的正确方以触发新关系在数据库中的持久化。
您可以想象拥有方是具有对另一方的引用的实体。 在您的摘录中,您有一对一的关系。 由于它是一种对称关系,如果对象 A 与对象 B 相关,那么您最终会得到它,反之亦然。
这意味着将对象 B 的引用保存到对象 A 中,而在对象 B 中保存对对象 A 的引用将是多余的:这就是为什么您选择哪个对象“拥有”另一个引用它的对象。
当您拥有一对多关系时,与“多”部分相关的对象将成为拥有方,否则您将不得不存储从单个对象到多个对象的多个引用。 为了避免这种情况,第二个类中的每个对象都将有一个指向它们所引用的单个对象的指针(因此它们是拥有方)。
对于多对多关系,因为无论如何您都需要一个单独的映射表,所以不会有任何拥有方。
总之,拥有方是具有对另一方的引用的实体。
双向关系必须遵循这些规则。
双向关系的反面必须通过使用@OneToOne、@OneToMany 或@ManyToMany 注释的mappedBy 元素来引用其拥有方。 mappingBy 元素指定作为关系所有者的实体中的属性或字段。
多对一双向关系的多方不能定义mappedBy 元素。 多方始终是关系的拥有方。 (根据 Oracle 文档: https : //docs.oracle.com/cd/E19798-01/821-1841/bnbqi/index.html )
对于一对一的双向关系,拥有方对应于包含相应外键的一方。
对于多对多双向关系,任何一方都可能是拥有方。
嗯,这有很大帮助。 我赞成这个讨论
特别是我在医院管理系统中寻找以下用例。 Patient->Patient History 1.Patient 不依赖于病史,即只有在 Patient 第一次访问医院时,才需要添加他的病史。 2. 在随后的访问中,历史记录被添加到历史表中,但需要一个对患者的患者 ID 引用。 所以这里作为外键在 PatientHIstory 表中,拥有方是 PatientHistory
所以这种关系必须被建模为双向 OneToMany,在患者实体中映射为 =“患者”。 每个实体相互引用。
我将非常简要地解释这一点。 “拥有”意味着本身带有外键列。 换句话说,它拥有这种关系。 许多人误解了拥有这个词。 他们认为拥有方是主要的一方。 但是当我们看它时,带有外键列的表是链接的一面。 例如:让我们考虑一下 Person 和 Adress 以及它们之间的关系 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 具有 adress_id fk 列,该列与主键列的 Adress 链接。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.