我有一个包含setup和release列的数据表,这两个列都包含时间戳。我的目标是使用CriteriaQuery创建一个与下面的SQL查询等效的查询。
SQL查询:SELECT TIMESTAMPDIFF(SECOND, setup, released)) as sum_duration FROM calls
CriteriaBuilder#diff()函数显然不起作用,因为它需要Numbers参数,所以我尝试使用CriteriaBuilder#函数:
EntityManager entityManager = emProvider.get();
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Integer> query = criteriaBuilder.createQuery();
Root<Thingy> thingyRoot = query.from(Thingy.class);
Path<DateTime> setup = root.get("setup");
Path<DateTime> release = root.get("release");
Expression secondLiteral = criteriaBuilder.literal("SECOND");
Expression func = criteriaBuilder.function("TIMESTAMPDIFF", Integer.class, secondLiteral, setup, release);
entityManager.createQuery(query).getResultList();
字符串
然而,当我尝试运行这段代码时,它抛出了一个异常;看起来字面量没有被呈现为常量,而是作为参数:
java.lang.IllegalStateException: No data type for node: org.hibernate.hql.internal.ast.tree.MethodNode
\-[METHOD_CALL] MethodNode: '('
+-[METHOD_NAME] IdentNode: 'TIMESTAMPDIFF' {originalText=TIMESTAMPDIFF}
\-[EXPR_LIST] SqlNode: 'exprList'
+-[NAMED_PARAM] ParameterNode: '?' {name=param0, expectedType=null}
+-[DOT] DotNode: 'cdr0_.setup' {propertyName=setup,dereferenceType=ALL,propertyPath=setup,path=generatedAlias0.setup,tableAlias=cdr0_,className=com.vtsl.domain.CDR,classAlias=generatedAlias0}
| +-[ALIAS_REF] IdentNode: 'cdr0_.id' {alias=generatedAlias0, className=com.vtsl.domain.CDR, tableAlias=cdr0_}
| \-[IDENT] IdentNode: 'setup' {originalText=setup}
\-[DOT] DotNode: 'cdr0_.release' {propertyName=release,dereferenceType=ALL,propertyPath=release,path=generatedAlias0.release,tableAlias=cdr0_,className=com.vtsl.domain.CDR,classAlias=generatedAlias0}
+-[ALIAS_REF] IdentNode: 'cdr0_.id' {alias=generatedAlias0, className=com.vtsl.domain.CDR, tableAlias=cdr0_}
\-[IDENT] IdentNode: 'release' {originalText=release}
型
因此,我尝试匿名重写LiteralExpression#render,以直接返回我提供给方法的字符串,然而,这导致了这个异常。
java.lang.IllegalStateException: No data type for node: org.hibernate.hql.internal.ast.tree.MethodNode
\-[METHOD_CALL] MethodNode: '('
+-[METHOD_NAME] IdentNode: 'TIMESTAMPDIFF' {originalText=TIMESTAMPDIFF}
\-[EXPR_LIST] SqlNode: 'exprList'
+-[IDENT] IdentNode: 'SECOND' {originalText=SECOND}
+-[DOT] DotNode: 'cdr0_.setup' {propertyName=setup,dereferenceType=ALL,propertyPath=setup,path=generatedAlias0.setup,tableAlias=cdr0_,className=com.vtsl.domain.CDR,classAlias=generatedAlias0}
| +-[ALIAS_REF] IdentNode: 'cdr0_.id' {alias=generatedAlias0, className=com.vtsl.domain.CDR, tableAlias=cdr0_}
| \-[IDENT] IdentNode: 'setup' {originalText=setup}
\-[DOT] DotNode: 'cdr0_.release' {propertyName=release,dereferenceType=ALL,propertyPath=release,path=generatedAlias0.release,tableAlias=cdr0_,className=com.vtsl.domain.CDR,classAlias=generatedAlias0}
+-[ALIAS_REF] IdentNode: 'cdr0_.id' {alias=generatedAlias0, className=com.vtsl.domain.CDR, tableAlias=cdr0_}
\-[IDENT] IdentNode: 'release' {originalText=release}
型
所以问题是:我怎样才能修复我试图做的这个操作,或者实现最初的目标?
我用的是Hibernate,数据库是MySQL。
5条答案
按热度按时间qzlgjiam1#
下面是对等价的JPA Criteria Query的解释,
SELECT * 来自TIMESTAMPDIFF(SECOND,setup,released)< 3600的调用;
首先,您必须创建单元表达式并从
BasicFunctionExpression
扩展它,其中将“SECOND”参数作为单元并仅覆盖其rendor(RenderingContext renderingContext)
方法。字符串
然后在JPA标准查询中使用这个单位表达式。
型
它起作用了。
deikduxw2#
我遇到了同样的问题:
SECOND
将被撇号包围,查询将抛出异常。我通过以下代码解决了这个问题:
字符串
这给了我同样的结果。
iaqfqrcu3#
字符串
用案例陈述来模拟它。
c6ubokkw4#
这里有一个比卡里德·沙阿的更一般的解决方案。
基本上,我们需要的是一个自定义的“opaque literal”
Expression
类,它能够将任意token表达式(如MONTH
、YEAR
、INTERVAL 1 DAY
等)作为函数参数传递给MySQL:字符串
你可以这样使用它:
型
7z5jn7bk5#
我在这里遇到了一个类似的问题,但有一个变化- Hibernate 6已经改变了很多,以至于“OpaqueLiteralExpression”答案所建议的内部API不再适用。
我设法解决了这个问题,通过使用原始的Hibernate标准生成器
字符串