Hibernate 中的 @MapsId 注解

在本文中,我们学习了如何在使用一对一关系时使用@MapsId注解实现共享主键策略。

在这个简短的教程中,我们将学习如何使用 Hibernate 注释@MapsId来实现共享主键策略。

首先,我们先了解一下@MapsId是什么。然后,我们将演示如何在实践中使用它。

@MapsId注释
JPA/Hibernate提供了几个方便的注释,我们可以用它们来完成对象关系映射的所有繁重工作。在这些注释中,我们发现了@MapsId。

简而言之,此注解简化了一对一关系,允许两个实体共享同一个主键。它通过告诉 Hibernate 将子实体的主键映射到其关联父实体的主键来帮助实现共享主键策略。

现在我们知道了@MapsId是什么,让我们深入了解如何在实践中使用它。

设置应用程序
为了说明此注释的用法,我们需要设置一个基本示例。让我们考虑一个经典情况,数据库中有两个表,Person和Address。在这里,我们假设这两个表共享一对一关系。每个人都有一个地址,每个地址属于一个人。

现在,我们将为这两个表创建相应的JPA 实体。让我们从Person实体类开始:

@Entity
public class Person {
    @Id
    private int id;
    private String firstName;
    private String lastName;
    @OneToOne(mappedBy = "person")
    private Address address;
   
// standards getters and setters
}

在这个例子中,我们通过标识符、名字、姓氏和地址来定义一个人。

通常,我们使用@Entity注释来表示Person类是 JPA 实体。此外,@Id标记表示主键的字段。此外,@OneToOne顾名思义,定义与Person实体作为非拥有方的一对一关联。

接下来,让我们创建Address实体类:

@Entity
public class Address {
    @Id
    private int id;
    private String street;
    private String city;
    private int zipode;
    @OneToOne
    @JoinColumn(name = "id")
    @MapsId
    private Person person;
   
// standards getters and setters
}

类似地,我们使用相同的注释来映射表Address。重要的部分是@MapsId注释标记的person属性。

这里我们指示 Hibernate 使用Person实体的主键值作为Address实体的主键值。换句话说,P erson和Address表将具有相同的主键值。

使用示例
作为一个基本且最明显的例子,我们将尝试插入具有特定标识符的Person实例。然后,我们将插入一个不指定id 的Address对象,看看会发生什么:

@Test
void givenPersonEntityWithIdentifier_whenAddingAddress_thenPersistWithSameIdentifier() {
    int personId = 3;
    Person person = new Person();
    person.setId(personId);
    person.setFirstName("Azhrioun");
    person.setLastName(
"Abderrahim");
    session.persist(person);
    Address address = new Address();
    address.setStreet(
"7 avenue berlin");
    address.setCity(
"Tamassint");
    address.setZipode(13000);
    address.setPerson(person);
    session.persist(address);
    Address persistedAddress = session.find(Address.class, personId);
    assertThat(persistedAddress.getId()).isEqualTo(personId);
}

我们可以看到,尽管我们一开始没有指定id ,但 Hibernate 会将具有与给定人员相同标识符的新记录插入到Address表中。

简而言之,@MapsId有助于轻松映射一对一关系,其中子实体中的外键也充当主键,允许两个实体共享相同的主键。

另一个重要警告是,如果没有@MapsId,我们将为子实体中的外键和主键定义两列。因此,使用@MapsId,我们可以通过为两者提供单一映射来避免这种重复。