Hibernate中@Struct注解类型

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

  • Hibernate 允许您通过@Struct注释类型为使用@Embeddable注释或@Embedded属性注释的类 指定结构化类型。
  • SQL:1999 标准中引入了对结构化用户定义类型(又称为结构化类型)的支持,这是对象关系 (ORM) 数据库的一项功能。

结构化或复合类型有其用例,特别是在 SQL:2016 标准中引入了对 JSON 的支持之后。这些结构化类型的值提供对其子部分的访问,并且没有像表中的行那样的标识符或主键。

@Struct用于映射结构化类型
考虑下面的Department类示例,该类具有@Embedded Manager类(结构化类型):

@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;
}

@Embeddable和@Struct注解之间的区别
用@Struct注解的类 将该类映射到数据库中的结构化用户定义类型。例如,如果没有@Struct注释,@Embedded Manager对象尽管是一个单独的类型,但仍将成为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
);

@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”。

JSON 映射
由于 JSON 是预定义的非结构化类型,因此无需定义类型名称或属性顺序。通过用 @JdbcTypeCode(SqlTypes.JSON)注释嵌入字段/属性,可将 @Embeddable 映射为 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

结论
@Embeddable和@Embeddable @Struct之间的区别在于:后者实际上是底层数据库中的用户定义类型(user-defined type )。虽然许多数据库支持用户定义类型,但支持@Struct注解的 hibernate 方言有:

  • Oracle
  • DB2
  • PostgreSQL