大佬教程收集整理的这篇文章主要介绍了在JPA条件查询的“具有”子句中使用“ case ... when ... then ... else ... end”构造,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
这不太可能是Hibernate中的错误。在制作给定的标准查询时存在技术错误。以相同的示例但形式更简单。
假设我们对生成以下SQL查询感兴趣。
SELECT
p.prod_ID,
p.prod_name,
CASE
WHEN sum(r.raTing_num)/count(disTinCT r.raTing_ID) IS NulL THEN 0
ELSE round(sum(r.raTing_num)/count(disTinCT r.raTing_ID))
END AS avg_raTing
FROM
product p
left OUTER JOIN
raTing r
ON p.prod_ID=r.prod_ID
GROUP BY
p.prod_ID,
p.prod_name
HAVING
CASE
WHEN sum(r.raTing_num)/count(disTinCT r.raTing_ID) IS NulL THEN 0
ELSE round(sum(r.raTing_num)/count(disTinCT r.raTing_ID))
END>=1
基于下表在MysqL中。
@H_254_7@mysqL> desc raTing; +-------------+---------------------+------+-----+---------+----------------+ | FIEld | Type | Null | Key | Default | Extra | +-------------+---------------------+------+-----+---------+----------------+ | raTing_ID | bigint(20) unsigned | NO | PRI | NulL | auto_increment | | prod_ID | bigint(20) unsigned | YES | Mul | NulL | | | raTing_num | int(10) unsigned | YES | | NulL | | | ip_address | varchar(45) | YES | | NulL | | | row_version | bigint(20) unsigned | NO | | 0 | | +-------------+---------------------+------+-----+---------+----------------+ 5 rows in set (0.08 seC)
此表raTing
与另一个表明显多到一的关系product
(prod_ID
是外键引用的主键prod_ID
的product
表)。
在这个问题中,我们只对子句中的CASE
构造感兴趣HAVING
。
以下条件查询,
CriteriaBuilder criteriaBuilder = entitymanager.getCriteriaBuilder();
Criteriaquery<Tuple> criteriaquery = criteriaBuilder.createTuplequery();
Root<Product> root = criteriaquery.from(entitymanager.getmetamodel().entity(Product.class));
ListJoin<Product, raTing> prodraTingJoin = root.join(Product_.raTingList, JoinType.left);
List<Expression<?>> Expressions = new ArrayList<Expression<?>>();
Expressions.add(root.get(Product_.prodID));
Expressions.add(root.get(Product_.prodName));
Expression<Integer> sum = criteriaBuilder.sum(prodraTingJoin.get(raTing_.raTingNum));
Expression<Long> count = criteriaBuilder.countdisTinct(prodraTingJoin.get(raTing_.raTingID));
Expression<number> quotExpression = criteriaBuilder.quot(sum, count);
Expression<Integer> roundExpression = criteriaBuilder.function("round", Integer.class, quotExpression);
Expression<Integer> SELEctExpression = criteriaBuilder.<Integer>SELEctCase().when(quotExpression.isNull(), criteriaBuilder.literal(0)).otherwise(roundExpression);
Expressions.add(SELEctExpression);
criteriaquery.multiSELEct(Expressions.toArray(new Expression[0]));
Expressions.remove(Expressions.size() - 1);
criteriaquery.groupBy(Expressions.toArray(new Expression[0]));
criteriaquery.having(criteriaBuilder.greaterThanorequalTo(SELEctExpression, criteriaBuilder.literal(1)));
List<Tuple> List = entitymanager.createquery(criteriaquery).getResultList();
for (Tuple tuple : List) {
System.out.println(tuple.get(0) + " : " + tuple.get(1) + " : " + tuple.get(2));
}
按预期生成以下正确的SQL查询。
SELEct
product0_.prod_ID as col_0_0_,
product0_.prod_name as col_1_0_,
case
when sum(raTingList1_.raTing_num)/count(disTinct raTingList1_.raTing_ID) is null then 0
else round(sum(raTingList1_.raTing_num)/count(disTinct raTingList1_.raTing_ID))
end as col_2_0_
from
projectdb.product product0_
left outer join
projectdb.raTing raTingList1_
on product0_.prod_ID=raTingList1_.prod_ID
group by
product0_.prod_ID ,
product0_.prod_name
having
case
when sum(raTingList1_.raTing_num)/count(disTinct raTingList1_.raTing_ID) is null then 0
else round(sum(raTingList1_.raTing_num)/count(disTinct raTingList1_.raTing_ID))
end>=1
从技术角度来看,请查看上述条件查询中的以下行。
criteriaquery.having(criteriaBuilder.greaterThanorequalTo(SELEctExpression, criteriaBuilder.literal(1)));
问题中类似的代码如下。
createquery.having(criteriaBuilder.greaterThanorequalTo(SELEctExpression, 1));
看到问题中的原始表达式做的完全相同:
Expression<Integer> SELEctExpression = criteriaBuilder.<Integer>SELEctCase()
.when(quotExpression.isNull(), 0)
.<Integer>otherwise(roundExpression);
尝试将该表达式传递给criteriaBuilder.greaterThanorequalTo()
以下对象。
criteriaquery.having(criteriaBuilder.greaterThanorequalTo(SELEctExpression, 0));
请特别注意greaterThanorequalTo()
上面的第二个参数。是的0
。criteriaBuilder.literal(0)
因此,应该是问题中提到的例外。
因此,CriteriaBuilder#literal(T
value)
在CriteriaBuilder#SELEctCase()
构造中使用表达式时,请始终坚持在上述必要时始终使用文字值。
在Hibernate 4.3.6最终版,Hibernate 5.0.5最终版上进行测试。稍后,我将尝试在Eclipselink(最终版2.6.1)上运行相同的查询。 不再有古怪之处。
Eclipselink的查询的修改版本完全没有问题,只不过Object
如果使用构造函数表达式代替Tuple
该问题,则它需要在构造函数参数(形式参数)中使用类型参数。这是Eclipselink中一个长期存在的错误,尚待修复-
以下条件查询计算不同产品组的平均评分。
CriteriaBuilder criteriaBuilder=entitymanager.getCriteriaBuilder();
CriteriaQuery<Tuple>criteriaQuery=criteriaBuilder.createQuery(Tuple.class);
Metamodel metamodel=entitymanager.getMetamodel();
EntityType<Product>entityType=metamodel.entity(Product.class);
Root<Product>root=criteriaQuery.from(entityTypE);
SetJoin<Product,RaTing> join = root.join(Product_.raTingSet,JoinType.LEFT);
Expression<number> quotExpression = criteriaBuilder.quot(criteriaBuilder.sum(join.get(RaTing_.raTingNum)),criteriaBuilder.count(join.get(RaTing_.raTingNum)));
Expression<Integer> roundExpression = criteriaBuilder.function("round",Integer.class,quotExpression);
Expression<Object> SELEctExpression = criteriaBuilder.SELEctCase().when(quotExpression.isNull(),0).otherwise(roundExpression );
criteriaQuery.SELEct(criteriaBuilder.tuple(root.get(Product_.prodId).alias("prodId"),SELEctExpression.alias("raTing")));
criteriaQuery.groupBy(root.get(Product_.prodId));
criteriaQuery.having(criteriaBuilder.greaterThanOrequalTo(roundExpression,0));
criteriaQuery.orderBy(criteriaBuilder.desc(root.get(Product_.prodId)));
TypedQuery<Tuple> typedQuery = entitymanager.createQuery(criteriaQuery);
List<Tuple> tuples = typedQuery.getResultList();
它生成以下SQL查询:
SELECT product0_.prod_id AS col_0_0_,CASE
WHEN Sum(raTingset1_.raTing_num) / Count(raTingset1_.raTing_num) IS
NULL THEN
0
ELSE round(Sum(raTingset1_.raTing_num) / Count(raTingset1_.raTing_num))
END AS col_1_0_
FROM social_networking.product product0_
LEFT OUTER JOIN social_networking.raTing raTingset1_
ON product0_.prod_id = raTingset1_.prod_id
GROUP BY product0_.prod_id
HAVING round(Sum(raTingset1_.raTing_num) / Count(raTingset1_.raTing_num)) >= 0
ORDER BY product0_.prod_id DESC
的case...when
结构取代null
值与0
,如果在指定的表达式case
子句进行评估以null
。
我需要case...when
在having
子句中使用相同的构造,以便group
by
可以通过用该构造所计算的值列表中的替换null
为来过滤由子句返回的行组。0``case...when
因此,该having
子句应像
HAVING
(CASE
WHEN Sum(raTingset1_.raTing_num)/Count(raTingset1_.raTing_num) IS
NULL THEN 0
ELSE round(sum(raTingset1_.raTing_num)/Count(raTingset1_.raTing_num))
END)>=0
如果在greaterThanOrequalTo()
方法中,可以给出SELEctExpression
代替,roundExpression
但是这是不可能的。这样做会生成一个编译时错误,指示Expression<Integer>
和之间的类型不匹配Expression<Object>
。
那么case...when
,该having
子句中如何与该子句具有相同的结构SELEct
?
我也尝试过删除Object
表达式的泛型类型参数,Expression
SELEctExpression
但这样做NullPointerException
会引发。
此外,别名(prodId
,raTing
作为中给出)SELEct
子句具有在生成的SQL没有影响,因为可以看到。为什么列在这里没有别名?我想念什么吗?
如果列是别名,那么应该可以having
像下面这样写子句。
having raTing>=0
和having
在标准的查询应该如下,
criteriaQuery.having(criteriaBuilder.greaterThanOrequalTo(join.<Integer>get("raTing"),0));
但是由于在SELEct
子句中列没有别名,因此会引发异常。
java.lang.IllegalArgumentexception: Unable to resolve attribute [raTing] against path [null]
如何解决这种情况?无论如何,Group
by
应该通过在子句中产生的值列表中替换null
为来过滤由返回的行。0``case...when``SELEct
我正在使用Hibernate 4.2.7 final提供的JPA 2.0。
编辑:
我尝试使用以下表达式:
Expression<Integer> SELEctExpression = criteriaBuilder.<Integer>SELEctCase()
.when(quotExpression.isNull(),0)
.<Integer>otherwise(roundExpression);
但是它导致抛出以下异常:
Caused by: java.lang.NullPointerException
at java.lang.Class.isAssignableFrom(Native Method)
at org.hibernate.ejb.criteria.ValueHandlerFactory.isNumeric(ValueHandlerFactory.java:69)
at org.hibernate.ejb.criteria.preDicate.ComparisonPreDicate.<init>(ComparisonPreDicate.java:69)
at org.hibernate.ejb.criteria.CriteriaBuilderImpl.greaterThanOrequalTo(CriteriaBuilderImpl.java:468)
接下来的表达式如何工作,
Expression<Integer> roundExpression = criteriaBuilder
.function("round",quotExpression);
两者具有相同的类型?
有没有办法将case...when
结构放在having
子句中?
编辑
将表达式类型更改为
Expression<Integer> SELEctExpression = criteriaBuilder
.<Integer>SELEctCase()
.when(quotExpression.isNull(),0)
.<Integer>otherwise(roundExpression);
因此,在 EclipseLink(2.3.2)中 工作时,可以在该having
子句中使用它。
对于Hibernate提供程序,NullPoiterExcpetion
如果尝试更改的表达式类型SELEctCase()
(Expression<Object>
默认返回),则抛出。
更新:
这个问题在Hibernate 5.0.5 final中仍然存在。
以上是大佬教程为你收集整理的在JPA条件查询的“具有”子句中使用“ case ... when ... then ... else ... end”构造全部内容,希望文章能够帮你解决在JPA条件查询的“具有”子句中使用“ case ... when ... then ... else ... end”构造所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。