API критериев Hibernate – как упорядочить по размеру коллекции?
-
12-09-2019 - |
Вопрос
Предполагая, что у меня есть классы User и UserGroup.Существует необязательная группа «1-многие» для ассоциации пользователей, и ассоциация сопоставляется с обеих сторон (сторона UserGroup через свойство под названием «members», которое является HashSet, сторона пользователя через свойство «группа»).
Как с помощью Criteria API запросить все группы, отсортированные по количеству членов группы?
(Редактировать) Когда я спрашивал об этом, я должен был указать, что разбиение на страницы выполняется в SQL, поэтому, если возможно, упорядочивание также должно выполняться в SQL.
Решение
Другой вариант — использовать аннотацию @Formula, которая по сути эквивалентна созданию вложенного выбора, чтобы вы могли получить свои значения.
В рассматриваемом свойстве/члене объектов БД (который вы должны создать) добавьте аннотацию к методу получения, например:
@Formula ("(выберите count (table_name.id) из таблицы, где что угодно ...)") public getnewproperty {return newproperty;}
Затем нацельтесь на члена напрямую, чтобы получить значения вашего счетчика...
Примечание:Имейте в виду, что при указании sql в аннотации формулы вы должны указывать имена полей непосредственно при ссылке на текущую таблицу объектов (this), поскольку спящий режим сам справляется с этим.Поэтому в вашем предложении WHERE просто используйте ID или что-то еще при ссылке на текущую таблицу объектов, которая, как я подозреваю, является UserGroup.
Мне нужен был установщик для моего нового свойства, чтобы спящий режим работал и не давал компилятору жаловаться.
Могут быть и другие умные способы использования @Formula, но я новичок в этом, и, похоже, документации по этому вопросу не так уж и много...
Если вы никогда раньше не использовали вложенные SELECTS, возможно, вам стоит сначала просто воссоздать их в sql - это мне помогло.
Надеюсь это поможет
Другие советы
По умолчанию это невозможно с использованием 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();
это будет список групп пользователей, упорядоченных по размеру участников по возрастанию, где «члены» — это коллекция пользователей в сущности UserGroup.
Вероятно, вы могли бы сделать это, определив «производное свойство» для вашей сущности, которое будет доступно только для чтения и возвращает размер коллекции внутри этой сущности.Самый простой способ определить производное свойство: задокументировано здесь:
Обновление, вставка (необязательно - по умолчанию true):Указывает, что сопоставленные столбцы должны быть включены в операторы SQL Update и/или вставить.Установка оба на false позволяет чистому «полученному» свойству, значение которого инициализируется из какого -либо другого свойства, которое отображается на одном и том же столбце (ы), или с помощью триггера или другого применения.
После определения свойства вы сможете использовать имя свойства в качестве условия заказа в API критериев, как и любое другое свойство.Хотя сам я этого не пробовал.
Если это сработает, то, скорее всего, это будет выполнено как сортировка в памяти, поскольку она не сможет сопоставить ее с SQL.Если это проблема, то по той же ссылке выше описано, как реализовать производное свойство с использованием специального фрагмента SQL:
Мощная особенность - это свойства.Эти свойства по определению только для чтения.Значение свойства вычисляется во время загрузки.Вы объявляете вычисление как выражение SQL.Затем это переводится на подложку Select Clause в запросе SQL, который загружает экземпляр: