使用JPA条件无法在MSSQL中调用FORMAT函数

问题描述

我正在尝试使用JPA条件执行此查询

我正在尝试使用JPA条件执行此查询

SELECT format(data_creazione_pratica,'dd/MM/yyyy')
FROM tcigdbexternal.ristoratori_svil.pratica

...所以我写了这个JAVA代码

final CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();                  
final CriteriaQuery<String> criteria = criteriaBuilder.createquery(String.class);            
final Root<Pratica> root = criteria.from(Pratica.class);                                     
criteria.select(criteriaBuilder.function("FORMAT",String.class,root.get("dataInserimento"),criteriaBuilder.literal("dd/MM/yyyy")));                                             

...但是我得到了这个异常:

task-1|ERROR|requestId_6|i.p.r.m.a.w.r.c.PraticaController[PraticaController.java:50]|Exception occurred
org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.QueryException: 
    No data type for node: org.hibernate.hql.internal.ast.tree.MethodNode    \-[METHOD_CALL] MethodNode: 'function (FORMAT)'      
        +-[METHOD_NAME] IdentNode: 'FORMAT' {originalText=FORMAT}      
            \-[EXPR_LIST] sqlNode: 'exprList'         
                +-[DOT] DotNode: 
                    'pratica0_.data_creazione_pratica' 
                    {propertyName=dataInserimento,dereferenceType=PRIMITIVE,getPropertyPath=dataInserimento,path=generatedalias0.dataInserimento,tableAlias=pratica0_,className=mypackage.Pratica,classAlias=generatedalias0}
                    |  +-[ALIAS_REF] IdentNode: 'pratica0_.id_pratica' {alias=generatedalias0,className=it.poste.ristoratori.ministero.application.entity.Pratica,tableAlias=pratica0_} 
                    |  \-[IDENT] IdentNode: 'dataInserimento' {originalText=dataInserimento}
            \-[QUOTED_STRING] LiteralNode: ''dd/MM/yyyy''
                    [select function('FORMAT',generatedalias0.dataInserimento,'dd/MM/yyyy')
                    from mypackage.Pratica as generatedalias0];
                    nested exception is java.lang.IllegalArgumentException: org.hibernate.QueryException:
                    No data type for node: org.hibernate.hql.internal.ast.tree.MethodNode    
            \-[METHOD_CALL] MethodNode: 'function (FORMAT)'
                +-[METHOD_NAME] IdentNode: 'FORMAT' {originalText=FORMAT}
                    \-[EXPR_LIST] sqlNode: 'exprList'
                    +-[DOT] DotNode: 'pratica0_.data_creazione_pratica' {propertyName=dataInserimento,classAlias=generatedalias0}
                    |  +-[ALIAS_REF] IdentNode: 'pratica0_.id_pratica'
                    {alias=generatedalias0,tableAlias=pratica0_}
                    |  \-[IDENT] IdentNode: 'dataInserimento' {originalText=dataInserimento}
                    \-[QUOTED_STRING] LiteralNode: ''dd/MM/yyyy''
                    [select function('FORMAT','dd/MM/yyyy')
                    from mypackage.Pratica as generatedalias0]
                    at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:374)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:257)

解决方法

这个解决方案对我有用

从 Hibernate 5.2.18 开始,即使您通过 JPA 引导,也可以使用 MetadataBuilderContributor 实用程序来自定义 MetadataBuilder。

MetadataBuilderContributor 接口可以这样实现:

public class SqlFunctionsMetadataBuilderContributor
    implements MetadataBuilderContributor {
     
 @Override
 public void contribute(MetadataBuilder metadataBuilder) {
    metadataBuilder.applySqlFunction(
        "group_concat",new StandardSQLFunction(
            "group_concat",StandardBasicTypes.STRING
        )
    );
 }
}

而且,我们可以通过 hibernate.metadata_builder_contributor 配置属性提供 SqlFunctionsMetadataBuilderContributor:

<property>
    name="hibernate.metadata_builder_contributor"
    value="com.vladmihalcea.book.hpjp.hibernate.query.function.SqlFunctionsMetadataBuilderContributor"
</property>

参考:https://vladmihalcea.com/hibernate-sql-function-jpql-criteria-api-query/