假设我有User和UserGroup类。有一个可选的1-many组到用户关联,并且关联是从两侧映射的(UserGroup端通过名为“members”的属性映射,这是一个HashSet,用户端通过属性“group”)。
使用Criteria API,如何查询所有组,按组成员的数量排序?
(编辑)当我问这个在SQL中执行分页时我应该指出,所以如果可能的话,也应该在SQL中执行排序。
答案 0 :(得分:4)
默认情况下,使用Citeria API是不可能的,但您可以扩展org.hibernate.criterion.Order类。 本文是关于如何扩展该类:http://blog.tremend.ro/2008/06/10/how-to-order-by-a-custom-sql-formulaexpression-when-using-hibernate-criteria-api
我的解决方案是:
public class SizeOrder extends Order {
protected String propertyName;
protected boolean ascending;
protected SizeOrder(String propertyName, boolean ascending) {
super(propertyName, ascending);
this.propertyName = propertyName;
this.ascending = ascending;
}
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
String role = criteriaQuery.getEntityName(criteria, propertyName) + '.' + criteriaQuery.getPropertyName(propertyName);
QueryableCollection cp = (QueryableCollection) criteriaQuery.getFactory().getCollectionPersister(role);
String[] fk = cp.getKeyColumnNames();
String[] pk = ((Loadable) cp.getOwnerEntityPersister())
.getIdentifierColumnNames();
return " (select count(*) from " + cp.getTableName() + " where "
+ new ConditionFragment()
.setTableAlias(
criteriaQuery.getSQLAlias(criteria, propertyName)
).setCondition(pk, fk)
.toFragmentString() + ") "
+ (ascending ? "asc" : "desc");
}
public static SizeOrder asc(String propertyName) {
return new SizeOrder(propertyName, true);
}
public static SizeOrder desc(String propertyName) {
return new SizeOrder(propertyName, false);
}
}
toSqlString方法基于org.hibernate.criterion.SizeExpression类。 (来源:http://javasourcecode.org/html/open-source/hibernate/hibernate-3.6.0.Final/org/hibernate/criterion/SizeExpression.java.html)
使用示例:
hibernateSession.createCriteria(UserGroup.class).addOrder( SizeOrder.asc("members") ).list();
这将列出按成员升序大小排序的用户组,其中“members”是UserGroup实体中的User集合。
答案 1 :(得分:1)
另一种选择是使用@Formula注释,它基本上相当于创建一个嵌套选择,这样你就可以得到你的数量。
在您的数据库对象属性/成员(您应该创建)中,将注释添加到getter中,如:
@Formula(“(SELECT COUNT(TABLE_NAME.ID)FROM TABLE WHERE what ...)”) public long getNewProperty { 返回newProperty; }
然后直接定位会员以获取您的计数值......
注意:请注意,在公式注释中指定sql时,必须在引用当前对象表(this)时直接指定字段名称,因为hibernate会自行处理。因此,在引用当前对象表时,在WHERE子句中只使用ID或其他任何东西,我怀疑它是UserGroup。
我必须为我的新属性设置一个setter才能让hibernate工作并防止编译器抱怨。
可能还有其他聪明的方法可以使用@Formula,但我对此很新,并且似乎没有关于这个主题的很多文档......
如果您以前从未使用过嵌套的SELECTS,那么您可能只想在sql中重新创建 - 这对我有帮助。
希望这有帮助
答案 2 :(得分:0)
您可能通过在您的实体上定义“派生属性”来实现这一点,该属性是一个只读属性,它返回该实体内集合的大小。定义派生属性的最简单方法是documented here:
更新,插入(可选 - 默认为 true):指定映射 列应包含在SQL中 UPDATE和/或INSERT语句。 将两者都设置为false允许纯粹 “衍生”属性,其值为 从其他一些财产初始化 映射到相同的列,或通过 触发器或其他应用程序。
定义属性后,您应该能够将属性名称用作条件API中的order子句,就像任何其他属性一样。不过,我自己也没试过。
如果它有效,它可能会作为内存中的排序完成,因为它无法将其映射到SQL。如果这是一个问题,那么上面的相同链接记录了如何使用自定义SQL片段实现派生属性:
衍生出强大的功能 属性。这些属性是由 只读定义。该物业 值在加载时计算。您 将计算声明为SQL 表达。然后转换为a SQL中的SELECT子句子查询 加载实例的查询: