#java #hibernate #criteria #criteria-api
#java #гибернация #критерии #критерии-api
Вопрос:
У меня есть класс, который содержит набор Bs.
Я хотел бы создать критерии гибернации, чтобы получить все A, для которых набор Bs является надмножеством некоторого заданного набора.
Чтобы привести пример:
допустим, у нас есть три объекта типа A
a1, который имеет набор Bs = [b1, b2, b3]
a2, с набором = [b3, b4, b5]
a3, с набором = [b3, b5]
предположим, я хочу получить все A таким образом, чтобы его набор содержал [b3, b5]. Тогда результатом были бы a2 и a3
Надеюсь, я ясно выразился. Заранее спасибо!
Руководство
Ответ №1:
Я решил это следующим образом. Было сложно понять, что это сработало, но это довольно просто, как только вы это увидите.
B[] subset = new B[] {b3, b5};
DetachedCriteria.forClass(A.class).createAlias("bs", "b");
for (B b : subset) {
criteria.add(Restrictions.eq("b.id", b.getId()));
}
Ответ №2:
Я считаю, что этот критерий сработал бы (при условии, что свойство на, A
которое содержит набор B
объектов, вызывается bs
):
DetachedCriteria.forClass(A.class).add(Restrictions.and(
Restrictions.in("bs", new B[] { b3, b5 }),
Restrictions.notIn("bs", DetachedCriteria.forClass(B.class).add(
Restrictions.notIn("this", new B[] { b3, b5 }))
)
));
Хотя, возможно, не очень эффективно.
Комментарии:
1. это не работает. В примере также будет возвращен a1, потому что у a1 есть ‘b’, который находится в { b3, b5 }.
2. ага. извините, что пропустил эту деталь. смотрите правку, которую я только что сделал. я не уверен, работает ли «это» в запросах критериев (на данный момент ускользает из моей головы), но если нет, то вы можете использовать идентификатор объекта.
Ответ №3:
Прежде чем думать о критериях, вам нужно сначала записать необработанный SQL.
Вы могли бы сделать это в SQL следующим образом (предполагая, что существует таблица, AB
объединяющая записи между A
и B
где fk_A
указано на id
in A
и fk_B
указывает на id
in B
):
SELECT fk_A, count(fk_B) FROM AB
WHERE fk_B IN (b3, b5)
GROUP BY fk_A
HAVING count(fk_B) = 2
Таким образом, вы не получите «неполные» записи из инструкции A
as HAVING count(fk_B)
, которая их фильтрует. Излишне говорить, что вам придется заменить 2
на соответствующее число, если количество Bs отличается.
Далее идет сложная часть преобразования этого в критерии 🙂 Некоторый псевдо (читай: непроверенный) код:
Criteria criteria = getSession().createCriteria(A.class);
criteria.add(Restrictions.in("fk_B", new String[] {b3, b5}));
ProjectionList projectionList = Projections.projectionList();
projectionList.add(Projections.count("fk_B"));
projectionList.add(Projections.groupProperty("fk_A"));
criteria.setProjection(projectionList);
Как вы можете видеть, в этом критерии все еще не хватает HAVING
бита. К сожалению, HAVING
пока не поддерживается в Criterions API. Однако вы должны получить список результатов и подсчетов и игнорировать те, где количество меньше требуемого.