最近项目中开始使用JPA,使用过程中有两个排序场景遇到的问题,在此将问题及解决方法作一个记录。
先抛出问题:
- model类A中包含Set<B>成员,即一对多关系,要求查询A的时候按A包含的B对象个数来排序。
- model类A中包含一个String s字段,该字段在数据库中保存的是"00/01/11"这样的数字字符串数据,但是在界面显示的是中文描述信息,这个中文描述信息与数据库中的数字字符串一一对应,要求按这个字段排序。
这里把类示例代码贴出来:
class A {
private String id;
@OneToMany
private Set<B> objBs;
}
class B {
private String id;
@ManyToOne
private A a;
}
问题1解决方法:
Expression<Integer> sum = cb.count(root.join("objBs", JoinType.LEFT)).as(Integer.class);
if (StringUtils.equals("DESC", localOrder)) {
return query.where(predicates.toArray(new Predicate[predicates.size()])).
groupBy(root.get("id").as(String.class)).orderBy(cb.desc(sum)).getRestriction();
}
return query.where(predicates.toArray(new Predicate[predicates.size()])).
groupBy(root.get("id").as(String.class)).orderBy(cb.asc(sum)).getRestriction();
问题2解决方法:
Expression<String> sStr = cb.selectCase()
.when(cb.equal(root.get("s").as(String.class), "00"),
Constants.pluginTypeMap.get("00"))
.when(cb.equal(root.get("s").as(String.class), "01"),
Constants.pluginTypeMap.get("01"))
.when(cb.equal(root.get("s").as(String.class), "10"),
Constants.pluginTypeMap.get("10"))
.when(cb.equal(root.get("s").as(String.class), "11"),
Constants.pluginTypeMap.get("11"))
.when(cb.equal(root.get("s").as(String.class), "12"),
Constants.pluginTypeMap.get("12"))
.when(cb.equal(root.get("s").as(String.class), "13"),
Constants.pluginTypeMap.get("13")).as(String.class);
if (StringUtils.equals("DESC", localOrder)) {
return query.where(predicates.toArray(new Predicate[predicates.size()]))
.orderBy(cb.desc(sStr)).getRestriction();
}
return query.where(predicates.toArray(new Predicate[predicates.size()]))
.orderBy(cb.asc(sStr)).getRestriction();
这样写以后报错:
at org.hibernate.jpa.criteria.expression.SearchedCaseExpression.render(SearchedCaseExpression.java:125)
根据报错的位置跟踪到源码
org.hibernate.jpa.criteria.expression.SearchedCaseExpression.render(RenderingContext)里面第二个caseStatement:
public String render(RenderingContext renderingContext) {
StringBuilder caseStatement = new StringBuilder( "case" );
for ( WhenClause whenClause : getWhenClauses() ) {
caseStatement.append( " when " )
.append( ( (Renderable) whenClause.getCondition() ).render( renderingContext ) )
.append( " then " )
.append( ( (Renderable) whenClause.getResult() ).render( renderingContext ) );
}
caseStatement.append( " else " )
.append( ( (Renderable) getOtherwiseResult() ).render( renderingContext ) )
.append( " end" );
return caseStatement.toString();
}
猜想是缺少一个otherWise(),于是改成:
Expression<String> sStr = cb.selectCase()
.when(cb.equal(root.get("s").as(String.class), "00"),
Constants.pluginTypeMap.get("00"))
.when(cb.equal(root.get("s").as(String.class), "01"),
Constants.pluginTypeMap.get("01"))
.when(cb.equal(root.get("s").as(String.class), "10"),
Constants.pluginTypeMap.get("10"))
.when(cb.equal(root.get("s").as(String.class), "11"),
Constants.pluginTypeMap.get("11"))
.when(cb.equal(root.get("s").as(String.class), "12"),
Constants.pluginTypeMap.get("12"))
.when(cb.equal(root.get("s").as(String.class), "13"),
Constants.pluginTypeMap.get("13")).
.otherWise("").as(String.class);
if (StringUtils.equals("DESC", localOrder)) {
return query.where(predicates.toArray(new Predicate[predicates.size()]))
.orderBy(cb.desc(sStr)).getRestriction();
}
return query.where(predicates.toArray(new Predicate[predicates.size()]))
.orderBy(cb.asc(sStr)).getRestriction();
bingo!问题解决!