Hibernate ORM 版本 6.2.0.Final 即将发布,以下文章将尝试解释该版本中新增的一个新特性。

组合 SQL 类型

长期以来,SQL 完全基于关系型,每个数据模型都必须建模为具有列和约束的表。然后出现了对象关系型热潮,SQL:1999 标准引入了对 结构化类型 的支持。随着 XML 热潮的到来,SQL:2003 标准增加了对 XML 的支持,而在 SQL:2016 标准中首次出现了对 JSON 的支持。

无论是有结构还是无结构的复合类型,都有其用例,因此 Hibernate 出现来对这些数据类型提供解决方案也是时候了。

这些复合类型的值提供了对其子部分的访问,并且不具有像表行那样的标识性。在 ORM 领域中,可嵌入类型具有相同的属性,因此允许映射到这些 SQL 类型是顺理成章的。

结构映射

现在可以通过使用 @Struct(name = "…") 注解可嵌入类型或 @Embedded 字段/属性来将可嵌入类型映射到命名 SQL 对象类型,也称为结构化类型。

hbm2ddl 架构生成工具支持生成 DDL 来创建和删除这些结构化类型。由于结构化类型属性顺序很重要,并且必须符合 Hibernate 的期望,因此用户可以在架构验证添加对结构化类型支持之前比较类型定义。

考虑以下简单的映射示例

@Embeddable
@Struct(name = "my_point")
public class Point {
        private int x;
        private int y;
}

将产生一个类似于以下架构

create type my_point as (
    x int not null,
    y int not null
)

可以通过在持久化属性上应用 @Column 来细化结构化列的名称和可空性。

@Entity
public class PointHolder {
        @Id
        private int id;
        @Column(name = "the_point", nullable = false)
        private Point p;
}

这将产生类似于以下架构

create table PointHolder as (
    id int not null primary key,
    the_point my_point not null
)

由于结构化类型属性的顺序至关重要,因此了解如何控制 Hibernate 的期望非常重要。有两种基本方法可以控制顺序

  • @Struct注解中指定attributes成员以定义顺序

  • 使用Java记录通过规范构造函数隐式指定顺序

第一种方法很简单。如果所需的顺序是(y,x),则Point嵌入类型需要通过使用@Struct(name = "my_point", attributes = {"y", "x"})来声明这一点。

第二种方法更有趣,因为它利用了Hibernate 6.2中引入的另一个新特性,即对Java记录的原生支持。

@Embeddable
@Struct(name = "my_point")
public record Point(int y, int x) {}

对于Java记录,不再需要@EmbeddableInstantiator,因为Hibernate现在根据规范构造函数自动配置合适的实例化器。规范构造函数中记录组件的顺序也代表了Hibernate期望结构化类型属性定义的顺序。

截至写作时,结构化类型支持仅实现于Oracle、PostgreSQL和DB2。

XML和JSON映射

由于XML和JSON是预定义的无结构类型,因此无需定义类型名或属性顺序。将嵌入类型映射为XML或JSON可以通过分别用@JdbcTypeCode(SqlTypes.SQLXML)@JdbcTypeCode(SqlTypes.JSON)注解@Embedded字段/属性来实现。

截至写作时,尚无数据库方言实现XML支持,所以以下将仅关注JSON部分,但未来将以相同方式应用于XML支持。
@Entity
public class JsonHolder {
        @Id
        private int id;
        @JdbcTypeCode(SqlTypes.JSON)
        @Column(name = "my_json", nullable = false)
        private Point point;
}

具有此类映射的实体将大致产生以下架构

create table JsonHolder as (
    id int not null primary key,
    my_json json not null,
    check (json_value(my_json, '$.x') is not null and json_value(my_json, '$.y') is not null)
)

如您所见,表定义包含一个检查约束,该约束通过访问json_value函数来强制嵌入类型在JSON值内的约束。

使用嵌入类型属性进行HQL查询

select j.point.x, j.point.y
from JsonHolder j

将解析为相应的json_value表达式

select json_value(j.point, '$.x'), json_value(j.point, '$.y')
from JsonHolder j

同样,赋值表达式将更新JSON文档的相关部分。

截至写作时,JSON支持仅实现于Oracle和PostgreSQL。

展望

在未来的版本中,我们计划添加对SQL Server上的struct类型的支持,以及对其他数据库的XMLJSON映射的支持。我们还将尝试放宽复合类型映射的限制,并启用关联映射以及数组映射的使用。

希望您喜欢这些新特性,并能在论坛或我们的聊天平台上提供反馈!


返回顶部