Hibernate 6 SQLFunctionTemplate 替代方案

6
我们有一个名为HibernateMetadataBuilderContributor的类,它可以在Hibernate 5或Spring Boot 2.7中正常工作。但是当我们迁移到Hibernate 6或Spring Boot 3时,它就无法正常工作了。
public class HibernateMetadataBuilderContributor implements MetadataBuilderContributor {

    public static final String STRING_AGG = "string_agg";
    public static final String STRING_AGG_ORDER_BY = "string_agg_order_by";
    public static final String STRING_AGG_DISTINCT = "string_agg_distinct";

    @Override
    public void contribute(final MetadataBuilder metadataBuilder) {
        metadataBuilder.applySqlFunction(STRING_AGG, new SQLFunctionTemplate(StandardBasicTypes.STRING, "string_agg(?1, ?2)"));
        metadataBuilder.applySqlFunction(STRING_AGG_ORDER_BY, new SQLFunctionTemplate(StandardBasicTypes.STRING, "string_agg(?1, ?2 order by ?3)"));
        metadataBuilder.applySqlFunction(STRING_AGG_DISTINCT, new SQLFunctionTemplate(StandardBasicTypes.STRING, "string_agg(distinct ?1, ?2)"));

    }
}

Hibernate 6 中找不到 SQLFunctionTemplate,有什么替代方案。

3个回答

3

Hibernate 5

在Hibernate 5中,这是我们用来注册具有多个参数的SQL函数的方法:

public class SqlFunctionsMetadataBuilderContributor implements MetadataBuilderContributor {
 
    @Override
    public void contribute(MetadataBuilder metadataBuilder) {
        metadataBuilder.applySqlFunction(
            "date_trunc",
            new SQLFunctionTemplate(
                StandardBasicTypes.TIMESTAMP,
                "date_trunc('day', (?1 AT TIME ZONE ?2))"
            )
        );
    }
}

Hibernate 6

在Hibernate 6中,可以像这样注册相同的函数:

public class SqlFunctionsMetadataBuilderContributor implements MetadataBuilderContributor {
 
    @Override
    public void contribute(MetadataBuilder metadataBuilder) {
        metadataBuilder.applySqlFunction(
            "date_trunc",
            DateTruncFunction.INSTANCE
        );
    }
 
    public static class DateTruncFunction extends NamedSqmFunctionDescriptor {
         
        public static final DateTruncFunction INSTANCE = new DateTruncFunction();
 
        public DateTruncFunction() {
            super(
                "date_trunc",
                false,
                StandardArgumentsValidators.exactly(2),
                null
            );
        }
 
        public void render(
                SqlAppender sqlAppender,
                List<? extends SqlAstNode> arguments,
                SqlAstTranslator<?> walker) {
            Expression timestamp = (Expression) arguments.get(0);
            Expression timezone = (Expression) arguments.get(1);
            sqlAppender.appendSql("date_trunc('day', (");
            walker.render(timestamp, SqlAstNodeRenderingMode.DEFAULT);
            sqlAppender.appendSql(" AT TIME ZONE ");
            walker.render(timezone, SqlAstNodeRenderingMode.DEFAULT);
            sqlAppender.appendSql("))");
        }
    }
}

但仍然会有一个折旧警告!我们是否有任何其他选择来使用{@link TypeContributor}、{@link FunctionContributor}或{@link AdditionalMappingContributor},而不是根据需要进行依赖。 - Arunkumar Pushparaj
但是仍然会有一个贬值警告!在需要的情况下,我们是否有其他替代方案可用,例如使用{@link TypeContributor},{@link FunctionContributor}或者{@link AdditionalMappingContributor}? - Arunkumar Pushparaj
但仍然会有折旧警告!我们是否有其他选择来使用{@link TypeContributor}、{@link FunctionContributor}或{@link AdditionalMappingContributor},而不是根据需要来决定? - undefined
@ArunkumarPushparaj 做你想在世界上看到的变化!Hibernate源代码是开源的,因此请随意调查另一种解决方案,并将其作为答案提供在这里。 - Vlad Mihalcea
@ArunkumarPushparaj 在这个世界上成为你想要看到的改变!Hibernate源代码是开源的,所以请随意调查替代方案,并在这里提供它作为答案。 - Vlad Mihalcea
由于它已经过时,是否有任何替代解决方案。 - undefined

1

以下方式似乎可以正常工作。

new PatternBasedSqmFunctionDescriptor(
                new PatternRenderer(pattern),
                null,
                null,
                null,
                name,
                FunctionKind.NORMAL,
                null
        );

是的,我猜那应该可以工作,但你不会得到任何良好的类型检查或其他东西。如果你用一些明智的东西填充这些空参数,HQL 将在类型方面做得更好。 - Gavin King
除了这些,PatternBasedSqmFunctionDescriptor中的其他参数都是接口,我必须实现它们,但我不确定该使用什么。 - Jana
好的,就像我在下面评论中提到的那样,你可以在StandardArgumentsValidatorsStandardFunctionReturnTypeResolversStandardFunctionArgumentTypeResolvers中找到实现。(它们非常琐碎。) - Gavin King

0

首先:您不需要在H6中这样做!

HQL现在带有内置的listagg()函数,对于那些称之为string_agg()的数据库,它会自动转换。请查看HQL用户指南章节以获取完整的内置可移植函数列表。

https://docs.jboss.org/hibernate/orm/6.2/userguide/html_single/Hibernate_User_Guide.html#hql-aggregate-functions-orderedset

现在,说完这些...

H6中与SQLFunction相对应的接口是SqmFunctionDescriptor,其中包含许多内置实现,您可以从中获得灵感,包括PatternBasedSqmFunctionDescriptor

但我们提供的基本、简化、"用户友好"的实现仍然是org.hibernate.dialect.function.StandardSQLFunction,现在已经适应了新的、更强大的SqmFunctionDescriptor框架。


我们也有Postgres的array_agg函数,那么Hibernate 6中是否有类似的函数呢?还有关于如何实现PatternBasedSqmFunctionDescriptor的示例吗? - Jana
啊,没错,array_agg 已经在待办事项清单上了:https://github.com/hibernate/hibernate-orm/discussions/5562 - Gavin King
我认为你不需要实现PatternBasedSqmFunctionDescriptor...你只需要实例化它,对吗? - Gavin King
你可能会喜欢 StandardArgumentsValidatorsStandardFunctionReturnTypeResolversStandardFunctionArgumentTypeResolvers 的帮助,但实际上只需要使用 new 创建它就可以了。 - Gavin King
@GavinKing,我在这里找到了这个线程,想知道 Hibernate 6 是否有内置的东西来替换我创建的自定义 CastInterval 函数,方法是通过覆盖 SQLFunctions 的 render 函数实现的,像这样:override fun render( firstArgumentType: Type?, args: List<*>, factory: SessionFactoryImplementor? ): String { return "cast(" + args[0] + " as interval)" } - Tim
1
很好的问题。目前在HQL6中,您可以将Duration转换为数字类型,但由于将Duration映射到SQL的复杂性,没有内置的方式来将某些东西强制转换为Duration。但它是我们想要的功能之一。如果这对您非常重要,那么提交一个问题可能会有所帮助。 - Gavin King

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接