1. 概述

在这个教程中,我们将回顾Hibernate的@Struct注解,它允许开发人员创建自定义结构化类型。

结构化用户定义类型(也称为结构类型)的支持在SQL:1999标准中引入,这是对象关系映射(ORM)数据库的一个特性。结构或复合类型有其特定的应用场景,特别是自从SQL:2016标准引入JSON支持以来。

这些结构类型值提供了访问其子部分的能力,不像表中的行,它们没有标识符或主键。

2. 结构映射

Hibernate通过@Struct注解类型让你能够为标注了@Embeddable注解的类或@Embedded属性指定结构化类型。

2.1. @Struct用于映射结构化类型

考虑一个Department类,它有一个@EmbeddedManager类(一个结构化类型):

@Entity
public class Department {
    @Id
    @GeneratedValue
    private Integer id;
    
    @Column
    private String departmentName;
    
    @Embedded
    private Manager manager;
}

下面是带有@Struct注解的Manager类定义:

@Embeddable
@Struct(name = "Department_Manager_Type", attributes = {"firstName", "lastName", "qualification"})
public class Manager {
    private String firstName;
    
    private String lastName;
    
    private String qualification;
}

2.2. @Embeddable@Struct注解的区别

@Struct注解的类将映射到数据库中的自定义结构化用户类型。例如,如果没有@Struct注解,@EmbeddedManager对象虽然是一个独立类型,但在Department表中会作为一部分,如下面的DDL所示:

CREATE TABLE DEPRARTMENT (
  Id BIGINT, 
  DepartmentName VARCHAR,
  FirstName VARCHAR,
  LastName VARCHAR,
  Qualification VARCHAR
);

带有@Struct注解的Manager类将生成类似以下的用户自定义类型:

create type Department_Manager_Type as (
    firstName VARCHAR,
    lastName VARCHAR,
    qualification VARCHAR 
)

添加@Struct注解后,Department对象如下面的DDL所示:

CREATE TABLE DEPRARTMENT (
Id BIGINT, 
DepartmentName VARCHAR,
Manager Department_Manager_Type
);

2.3. @Struct注解与属性顺序

由于结构类型具有多个属性,正确地将数据映射到相应的属性非常重要。一种定义属性顺序的方法是通过@Struct注解的attributes字段。

在上面的Manager类中,可以看到@Struct注解的attributes字段,它指定Hibernate在序列化和反序列化时期望Manager属性的顺序为“firstName”,“lastName”最后是“qualification”。

另一种定义属性顺序的方法是通过Java记录,通过规范构造函数隐式指定顺序,例如:

@Embeddable
@Struct(name = "Department_Manager")
public record Manager(String lastName, String firstName, String qualification) {}

在这种情况下,Manager记录的属性顺序将是“lastName”,“firstName”和“qualification”。

3. JSON映射

由于JSON是一种预定义的无结构类型,不需要定义类型名称或属性顺序。将@Embeddable作为JSON映射可以通过在嵌入的字段/属性上使用@JdbcTypeCode(SqlTypes.JSON)注解来完成。

例如,下面的类包含一个Manager对象,它也是一个JSON无结构类型:

@Entity
public class Department_JsonHolder {
    @Id
    @GeneratedValue
    private int id;
    
    @JdbcTypeCode(SqlTypes.JSON)
    @Column(name = "department_manager_json")
    private Manager manager;
}

上面类的预期DDL如下:

create table Department_JsonHolder as (
    id int not null primary key,
    department_manager_json json
)

以下是查询department_manager_json列属性的HQL示例:

select djh.manager.firstName, djh.manager.lastName, djh.manager.qualifications
from department_jsonholder djh

4. 总结

@Embeddable@Embeddable @Struct的主要区别在于后者在底层数据库中实际上是用户自定义类型。尽管许多数据库支持用户定义类型,但支持@Struct注解的Hibernate方言包括:

  • Oracle
  • DB2
  • PostgreSQL

在这篇文章中,我们讨论了Hibernate的@Struct注解,如何使用它,以及何时将其添加到领域类中。

本文的源代码可在GitHub上获取。