2013-07-17 3 views
19

У меня есть класс Cat и класс Owner. У кота есть один владелец, но у владельца может быть много кошек. Я хочу запросить «получить всех владельцев, у которых есть кошка с голубыми глазами».Критерий Hibernate присоединяется к запросу один к большому числу

class Cat{ 
Owner owner; //referenced from Owner.id 
String eyeColor; 
} 

class Owner{ 
List<Cat> catList; 
} 

Я пробовал некоторые коды, но я действительно не знаю, что делать.

Criteria criteria = getCurrentSession().createCriteria(cat.getClass(), "cat"); 
criteria.createAlias("cat.owner", "owner");  
criteria.add(Restrictions.eq("cat.eyeColor", "blue"); 
+1

Является ли связь двунаправленной? Почему бы не использовать HQL для такого статического запроса? –

+0

@ JBNizet извините, но у меня нет выбора, как использовать HQL. – hellzone

+0

Является ли связь двунаправленной? Почему у вас нет выбора? Это как плотник, которому не разрешено использовать молоток! –

ответ

34

Критерии могут отображать только проекции или корневую сущность. Не какая-то объединенная сущность. Таким образом, некоторые запросы невозможно выразить с помощью критериев (что является еще одной веской причиной использования HQL, в дополнение к гораздо большей читаемости и краткости).

Все здесь не потеряно, потому что ваша ассоциация двунаправленная. Так что вам просто нужно эквивалент запроса HQL

select distinct owner from Owner owner 
join owner.cats cat 
where cat.eyeColor = 'blue' 

Который является

Criteria c = session.createCriteria(Owner.class, "owner"); 
c.createAlias("owner.cats", "cat"); 
c.add(Restrictions.eq("cat.eyeColor", "blue"); 
c.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY); 
+0

В моем случае кошка знает хозяина, но владелец не знает о своих кошках. Как будет выглядеть критерий? – Kayser

+0

Как было сказано в моем ответе, AFAIK (если только это не было возможным в более новых версиях), использование критериев невозможно. Используйте HQL или используйте API критериев JPA2. –

+0

Это делает «отличную» операцию в памяти. Если у одного владельца есть миллион голубоглазых кошек, он вытащит их из базы данных, чтобы найти единственного владельца (пример, вероятно, не случайный случай, если вы не знаете реальную мощность). См. Мой ответ, как это можно сделать в базе данных. – Oliv

4

Попробуйте это:

DetachedCriteria dc = DetachedCriteria.forClass(Cat.class, "inner") 
    .add(Restrictions.eq("eyeColor", "blue")) 
    .add(Restrictions.eqProperty("inner.owner", "outer.pk")); 

session.createCriteria(Owner.class, "outer") 
    .add(Subqueries.exists(dc)) 
    .list(); 

Это может использовать индекс в базе данных и не будет делать по прибытии -memory distinct как в версии @JB Nizet (см. мой комментарий там). Индекс будет:

CREATE INDEX idx_cat_owner_eyecolor ON Cat(fkOwner, eyeColor) 

Придумайте distinct операции (либо в SQL или в памяти) в качестве кодового запаха. Он редко используется, и многие начинающие программисты используют его для устранения проблемы «почему у меня есть эта строка дважды». Его можно почти всегда переписывать, например, в этом случае. Случаев использования, когда это необходимо, мало.

Смежные вопросы