使用 Spring Boot 的 JPA / Hibernate 复合主键示例

x33g5p2x  于2021-10-20 转载在 其他  
字(6.2k)|赞(0)|评价(0)|浏览(336)

在本文中,您将学习如何使用 JPA 的 @Embeddable@EmbeddedId 注释在 Hibernate 中映射复合主键。

假设我们有一个管理不同公司员工的应用程序。每个员工在其公司内都有一个唯一的员工 ID。但是相同的employeeId 也可以存在于其他公司中,因此我们不能仅通过employeeId 来唯一标识一个雇员。

为了唯一地识别员工,我们需要知道他的员工 ID 和公司 ID。查看以下 Employees 表,其中包含一个复合主键,其中包括 employeeId 和 companyId 列 -

让我们从头开始创建一个项目,并学习如何使用 JPA 和 Hibernate 映射这样的复合主键。

创建项目

您可以通过在终端中键入以下命令,使用 Spring Boot CLI 快速生成项目 -

spring init -n=jpa-composite-primary-key-demo -d=web,jpa,mysql --package-name=com.example.jpa jpa-composite-primary-key-demo

或者,您也可以使用 Spring Initializr 网络应用程序来生成项目。按照以下说明使用 Spring Initializr Web 应用程序生成应用程序 -

1.打开http://start.spring.io
1.输入Artifact为“jpa-composite-primary-key-demo”

  1. 单击 Options 下拉列表以查看与项目元数据相关的所有选项。
  2. 包名称更改为“com.example.jpa”
  3. 选择WebJPAMysql 依赖项。
    1、点击Generate生成并下载工程。

以下是完整应用的目录结构,供大家参考——

您的引导项目不会有 modelrepository 包和所有其他类。我们将在继续下一节时创建它们

配置数据库和休眠日志级别

让我们在 src/main/resources/application.properties 文件中添加 MySQL 数据库 URL、用户名和密码配置 -

# DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
spring.datasource.url=jdbc:mysql://localhost:3306/jpa_composite_pk_demo?useSSL=false&serverTimezone=UTC&useLegacyDatetimeCode=false
spring.datasource.username=root
spring.datasource.password=root

# Hibernate

# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect

# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto = update

logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type=TRACE

除了 MySQL 数据库配置,我还指定了休眠日志级别和其他属性。

属性 spring.jpa.hibernate.ddl-auto = update 使应用程序中的实体类型和映射的数据库表保持同步。每当您更新域实体时,数据库中相应的映射表也会在您下次重新启动应用程序时更新。

这对开发非常有用,因为您不需要手动创建或更新表。它们将根据应用程序中的实体类自动创建/更新。

在继续下一部分之前,请确保您创建了一个名为 jpa_composite_pk_demo 的 MySQL 数据库,并根据您的 MySQL 安装更改 spring.datasource.usernamespring.datasource.password 属性。

定义域模型

复合主键在休眠中使用 Embeddable 类型映射。我们将首先创建一个名为 EmployeeIdentity 的 Embeddable 类型,其中包含 employeeId 和 companyId 字段,然后创建将嵌入 EmployeeIdentity 类型的 Employee 实体。

com.example.jpa 包中创建一个名为 model 的新包,然后在 model 包中添加以下类 -

1. EmployeeIdentity - 可嵌入类型

package com.example.jpa.model;

import javax.persistence.Embeddable;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.io.Serializable;

@Embeddable
public class EmployeeIdentity implements Serializable {
    @NotNull
    @Size(max = 20)
    private String employeeId;

    @NotNull
    @Size(max = 20)
    private String companyId;

    public EmployeeIdentity() {

    }

    public EmployeeIdentity(String employeeId, String companyId) {
        this.employeeId = employeeId;
        this.companyId = companyId;
    }

    public String getEmployeeId() {
        return employeeId;
    }

    public void setEmployeeId(String employeeId) {
        this.employeeId = employeeId;
    }

    public String getCompanyId() {
        return companyId;
    }

    public void setCompanyId(String companyId) {
        this.companyId = companyId;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        EmployeeIdentity that = (EmployeeIdentity) o;

        if (!employeeId.equals(that.employeeId)) return false;
        return companyId.equals(that.companyId);
    }

    @Override
    public int hashCode() {
        int result = employeeId.hashCode();
        result = 31 * result + companyId.hashCode();
        return result;
    }
}

2. 员工 - 域模型

package com.example.jpa.model;

import org.hibernate.annotations.NaturalId;
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Email;
import javax.validation.constraints.Size;

@Entity
@Table(name = "employees")
public class Employee {

    @EmbeddedId
    private EmployeeIdentity employeeIdentity;

    @NotNull
    @Size(max = 60)
    private String name;

    @NaturalId
    @NotNull
    @Email
    @Size(max = 60)
    private String email;

    @Size(max = 15)
    @Column(name = "phone_number", unique = true)
    private String phoneNumber;

    public Employee() {

    }

    public Employee(EmployeeIdentity employeeIdentity, String name, String email, String phoneNumber) {
        this.employeeIdentity = employeeIdentity;
        this.name = name;
        this.email = email;
        this.phoneNumber = phoneNumber;
    }

    // Getters and Setters (Omitted for brevity)
}

Employee 类中,我们使用 @EmbeddedId 注释嵌入 EmployeeIdentity 类型并将其标记为主键。

创建存储库

接下来,让我们创建用于从数据库访问 Employee 数据的存储库。首先,在 com.example.jpa 包内新建一个名为 repository 的包,然后在 repository 包内添加如下接口——

package com.example.jpa.repository;

import com.example.jpa.model.Employee;
import com.example.jpa.model.EmployeeIdentity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface EmployeeRepository extends JpaRepository<Employee, EmployeeIdentity> {

}

测试复合主键映射的代码

最后,让我们编写一些代码来测试复合主键映射。打开主类 JpaCompositePrimaryKeyDemoApplication.java 并将其替换为以下代码 -

package com.example.jpa;

import com.example.jpa.model.Employee;
import com.example.jpa.model.EmployeeIdentity;
import com.example.jpa.repository.EmployeeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class JpaCompositePrimaryKeyDemoApplication implements CommandLineRunner {

    @Autowired
    private EmployeeRepository employeeRepository;

    public static void main(String[] args) {
        SpringApplication.run(JpaCompositePrimaryKeyDemoApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        // Cleanup employees table
        employeeRepository.deleteAllInBatch();

        // Insert a new Employee in the database
        Employee employee = new Employee(new EmployeeIdentity("E-123", "D-457"),
                "Rajeev Kumar Singh",
                "rajeev@callicoder.com",
                "+91-9999999999");

        employeeRepository.save(employee);
    }
}

我们首先清理 Employee 表,然后插入一个带有员工 ID 和公司 ID 的新员工记录来测试设置。

您可以通过在项目的根目录中键入 mvn spring-boot:run 来运行该应用程序。一旦应用程序成功启动,Employee 记录将被插入到数据库中。

使用复合主键查询

现在让我们看一些使用复合主键的查询示例 -

1.使用复合主键检索员工 - (employeeId and companyId)

// Retrieving an Employee Record with the composite primary key
employeeRepository.findById(new EmployeeIdentity("E-123", "D-457"));

2.检索特定公司的所有员工

假设您想通过 companyId 检索公司的所有员工。为此,只需在 EmployeeRepository 接口中添加以下方法。

@Repository
public interface EmployeeRepository extends JpaRepository<Employee, EmployeeIdentity> {
    /* Spring Data JPA will automatically parse this method name and create a query from it */
    List<Employee> findByEmployeeIdentityCompanyId(String companyId);
}

就这样!你不需要实现任何东西。 Spring Data JPA 将使用方法名称动态生成查询。您可以在主类中使用上述方法来检索公司的所有员工,如下所示 -

// Retrieving all the employees of a particular company
employeeRepository.findByEmployeeIdentityCompanyId("D-457");

相关文章