持久性顶部

通过引用开始使用Spring Data JPA学习Spring Data JPA课程:

1188金宝搏亚洲

1.概述

在本教程中,我们会看到多种方式使用JPA处理多对多关系。

我们将使用学生,课程和各种关系的模型。

为简单起见,在代码示例中,我们只会显示与多对多关系相关的属性和JPA配置。

进一步阅读:

使用JPA将实体类名映射到SQL表名

了解表名在默认情况下是如何生成的,以及如何覆盖该行为。

JPA/Hibernate级联类型概述

快速实际概述JPA / Hibernate级联类型。

2.基本的多对多

2.1。建模多对多关系

关系是两种实体之间的连接。在多对多关系的情况下,双方都可以与另一方的多个实例相关联。

请注意,实体类型可能与其自身存在关系。考虑为家谱建金宝搏官网188be模的例子:每个节点都是一个人,因此如果我们讨论父子关系,那么两个参与者都是一个人。

但是,我们讨论单个或多个实体类型之间的关系并没有什么不同。金宝搏官网188be因为考虑两种不同实体类型之间的关系更容易,所以我们将使金宝搏官网188be用它们来说明我们的案例。

让我们借鉴他们喜欢的课程的学生的例子。

学生可以喜欢许多课程,许多学生可以喜欢同一门课程:

我们知道,在rdbms中,我们可以使用外键创建关系。因为双方都应该能够引用对方,我们需要创建一个单独的表来保存外键:

这样的表被称为a连接表。在连接表中,外键的组合将是其复合主键。

2.2。在JPA实现

建模与pojo的多对多关系是很容易的。我们应该包括一个集合在这两个类,它包含其他元素。

在那之后,我们需要用@ entity和主要键@ID使他们成为合适的JPA实体。

此外,我们应该配置关系类型。所以,我们标志着收藏品@manytomany.注释:

@entity类学生{@id long id;@manytomany set <课程> likedcourses;//其他属性//标准构造函数,getters和setter} @entity类课程{@id long id;@manytomany set <学生>喜欢;//其他属性//标准构造函数,getters和setter}

此外,我们必须配置如何在RDBMS中对关系建模。

所有者端是我们配置关系的地方。我们将使用学生类。

我们可以用这个@JoinTable注释在学生类。我们提供连接表的名称(course_like)以及外键@JoinColumn注释。这joinColumn属性将连接到关系的所有者端,而eversejoincolumn.到另一边:

@ManyToMany @JoinTable(name = "course_like", joinColumns = @JoinColumn(name = "student_id"), inverseJoinColumns = @JoinColumn(name = "course_id")) Set likedCourses;

注意使用@JoinTable甚至@JoinColumn不需要。JPA将为我们生成表和列名称。但是,策略JPA使用不会始终匹配我们使用的命名约定。因此,我们需要配置表和列名的可能性。

在目标端,我们只需要提供映射关系的字段名。

因此,我们设置的mappedBy的属性@manytomany.注释在课程类:

@ManyToMany(mappedBy = "likedCourses") Set likes;

请记住多对多的关系没有数据库中的所有者侧,我们可以配置连接表课程类并引用它学生类。

3.多对多使用复合键

3.1。建模的关系属性

让我们说我们想让学生评价课程。学生可以评价任意数量的课程,并且任何数量的学生都可以评价相同的课程。因此,这也是许多偏爱的关系。

让这个例子更复杂的是除了评级关系的存在,还有更多的因素。我们需要存储学生在课程上给出的评分分数。

我们在哪里可以存储这些信息?我们不能把它放在学生因为一个学生可以给不同的课程不同的评级。类似地,将它存储在课程实体也不是一个好的解决方案。

这是一种情况关系本身有一个属性。

使用这个示例,将属性附加到一个关系中,在ER图中如下所示:

我们可以模拟几乎与简单的多对多关系相同。唯一的区别是我们向联接表附加了一个新属性:

3.2。在JPA中创建复合键

实施一个简单的多对多关系相当简单。唯一的问题是,由于我们直接连接实体,我们无法将属性添加到关系中。所以,我们无法向关系本身添加属性。

由于我们将DB属性映射到JPA中的类字段,我们需要为这个关系创建一个新的实体类。

当然,每个JPA实体都需要主键。因为我们的主键是一个组合键,所以我们必须创建一个新类来保存键的不同部分:

@嵌入式类CourseRatingKey实现Serializable {@Column(name = "student_id") Long studententid;@Column(name = "course_id") Long courseId;//标准的构造函数,getter和setter

请注意,复合关键类必须满足一些关键要求:

  • 我们必须标记它@embeddable.
  • 它必须实现java.io.Serializable
  • 我们需要提供一个实施hashcode ()等于()方法。
  • 所有字段本身都不能是一个实体。

3.3。在JPA中使用复合键

使用这个组合键类,我们可以创建实体类,它为连接表建模:

@Entity class CourseRating {@EmbeddedId CourseRatingKey id;@ManyToOne @MapsId(" student_id") @JoinColumn(name = "student_id")学生学生;@ManyToOne @MapsId("courseId") @JoinColumn(name = "course_id")课程课程;int评级;//标准构造函数,getter和setter}

此代码与常规实体实现非常类似。但是,我们有一些关键差异:

  • 我们用了@EmbeddedId标记主键的一个实例CourseRatingKey类。
  • 我们标志着这一点学生课程字段@MapsId

@MapsId意味着我们将这些字段绑定到密钥的一部分,并且它们是多对一关系的外键。我们需要它,因为如上所述,我们不能在复合键中拥有实体。

在此之后,我们可以配置逆引用学生课程实体:

class Student{//…@OneToMany(mappedBy = "student") Set ratings;/ /……} class class{//…@OneToMany(mappedBy = "course") Set ratings;/ /……}

注意,还有一种使用组合键的替代方法@IdClass注释。

3.4。进一步的特征

我们配置了到学生课程课程@manytoone.。我们可以这样做,因为新实体我们在结构上分解了两个多对一关系的多对多关系。

为什么我们能够这样做?如果我们在前一个情况下密切检查表格,我们可以看到它包含两个多对一的关系。换句话说,在RDBMS中没有任何多对多的关系。我们称之为我们创建的结构,使用加入表多对多关系,因为这就是我们模型的。

此外,如果我们谈论多对多的关系,更清楚,因为这是我们的意图。金宝搏官网188be同时,加入表只是一个实现细节;我们真的不关心它。金宝搏官网188be

此外,这个解决方案还有一个我们还没有提到的附加特性。简单的多对多解决方案创建两个实体之间的关系。因此,我们不能将关系扩展到更多的实体。但我们在这个解中没有这个极限我们可以在任何数量的实体类型之间建模关系。

例如,当多个教师可以教授一门课程时,学生可以评价特定教师教授特定课程的方式。这样,评级将是三个实体之间的关系:学生,课程和老师。

4.使用新实体的多对多

4.1。建模的关系属性

假设我们想让学生注册课程。同时,当学生注册特定课程时,我们需要存储点。最重要的是,我们想存储她在课程中收到的成绩。

在理想情况下,我们可以用前面的解决方案来解决这个问题,其中我们有一个具有复合键的实体。然而,世界远非理想,学生并不总是在第一次尝试就完成了一门课程。

在这种情况下,有同一个学生课程对之间的多个连接或多行,使用相同的student_id-course_id对。我们不能使用前面的任何解决方案对它进行建模,因为所有主键都必须是唯一的。因此,我们需要使用一个单独的主键。

所以,我们可以引入一个实体,这将持有注册的属性:

在这种情况下,注册实体表示关系在其他两个实体之间。

因为它是一个实体,所以它将有自己的主键。

在前面的解决方案中,请记住,我们有一个由两个外键创建的复合主键。

现在这两个外键不再是主键的一部分:

4.2。在JPA实现

自从此以来course_registration成为一个常规表,我们可以创建一个普通的旧JPA实体建模:

@Entity class courserregistration {@Id Long id;@ManyToOne @JoinColumn(name = "student_id")学生学生;@ManyToOne @JoinColumn(name = "course_id")课程;LocalDateTime registeredAt;int年级;//其他属性//标准构造函数,getters和setter}

我们还需要配置这些关系学生课程课程:

class Student{//…@OneToMany(mappedBy = "学生")Set< courserregistration > registration;/ /……} class class{//…@OneToMany(mappedBy = "courses") Set< courserregistration > registration;/ /……}

再次,我们早先配置了这一关系,所以我们只需要告诉JPA,它可以找到该配置。

我们还可以使用此解决方案来解决学生评级课程的先前问题。但是,除非我们必须,否则创建专用主键感到很奇怪。

此外,从RDBMS的角度来看,这并没有多大意义,因为将两个外键组合在一起可以得到完美的组合键。此外,,组合键有一个明确的含义:我们在关系中连接哪些实体。

否则,这两种实现之间的选择通常只是个人偏好。

结论

在本文中,我们了解了什么是多对多关系,以及如何使用JPA在RDBMS中对其建模。

我们看到了在JPA中建模它的三种方法。在这些方面,这三种方法各有优缺点:

  • 代码清晰度
  • DB清晰
  • 能够为关系分配属性
  • 我们可以将多少实体与这个关系联系起来
  • 支持同一实体之间的多个连接

像往常一样,可以使用示例在github上

坚持下
通过引用开始使用Spring Data JPA学习Spring Data JPA课程:1188金宝搏亚洲
本文评论关闭!