在本课中,我们将学习如何使用连接表实现多对多的关系。

每项赛事都有一些比赛类别,如男子和/或女士的单打和双打。此外,所有四个大满贯赛事都有混合双打类别。其他不太知名的类别是轮椅网球和沙滩网球。这种情况很适合多对多的关系,即许多类别都是锦标赛的一部分,许多锦标赛都有相同的比赛类别。

一个比赛有很多类别,一个类别包含在很多比赛中。

一个比赛有很多类别,一个类别包含在很多比赛中。

我们已经在之前的一课中创建了Tournament类。在这一课中,我们将创建Category类,然后用多对多的关系将二者连接起来。在数据库中,这种关系是用一个连接表来建模的,该表在关系中拥有两个表的主键。

多对多的关系是用一个连接表来实现的。

多对多的关系是用一个连接表来实现的。

我们还将模拟两个现实生活中的约束。

  1. 对于多对多的数据库关系的例子,创建一个包manytomany,并将bi包中的所有文件复制到onetomany包内。这些文件包括PlayerPlayerProfileRegistrationTournament类以及相关的数据接入层、服务层和控制器类。

我们将首先在io.datajek.databaseelationships.manytomany包中创建一个新类,Category。这个类有两个字段,idname,其中id是主键。由于我们不希望相同的类别名称出现一次以上,我们将使用@Column注解的unique属性来施加唯一键约束。

package io.datajek.databaserelationships.manytomany;

@Entity
public class Category {
    @Id 
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int id;
 
    @Column(unique=true)
    private String name;
    //constructors
    //getters and setters
}

@Column(unique=true)确保同一类别名称不会被多次输入。

  1. 对于多对多的关系,任何一方都可以成为所有者。这取决于业务规则是如何定义的。比方说,我们不能有一个没有附加类别的锦标赛,但我们可以有一个不与任何锦标赛相关联的类别。考虑到这种情况,一个类别可以单独存在,但一个锦标赛需要有一个或多个类别与之关联。所以,Category成为拥有方,Tournament成为被引用方。

    在一个单向的多对多的关系中,我们把关系放在子方。所以,在Tournament类中,我们必须放一个指向Category类的链接。由于一个锦标赛可以有不止一个类别,我们将创建一个CategoryList,如下所示。

    @Entity
    public class Tournament {
        //...
    
        private List<Category> playingCategories = new ArrayList<>();
    
        //...
    }
    

为这个字段创建一个gettersetter方法。

@ManyToMany

  1. @ManyToMany注解被用来在两个实体之间创建多对多的关系。

    @ManyToMany
    private List<Category> playingCategories = new ArrayList<>();
    

@JoinTable

  1. 多对多的关系与我们到目前为止看到的关系不同。在这里,外键被存储在一个单独的表中,称为连接表,而不是放在父表或子表中。连接表连接两个表并包含两个表的外键。锦标赛和类别表不包含彼此的键,而是这两个表的主键都在连接表中。

    截屏2022-05-27 21.11.59.png

joinColumnsinverseJoinColumns