Критерии гибернации с ограничениями на детей - PullRequest
8 голосов
/ 10 августа 2011

У меня есть вызов критерия Hibernate, который я хочу выполнить в одном операторе SQL.То, что я пытаюсь сделать, это выбрать экземпляры Parent, у которых есть Children со свойством в диапазоне значений (предложение SQL IN), при загрузке дочерних элементов с использованием внешнего объединения.Вот что у меня есть:

 Criteria c = session.createCriteria(Parent.class);

 c.createAlias("children", "c", CriteriaSpecification.LEFT_JOIN)
          .setFetchMode("c", FetchMode.JOIN)
          .add(Restrictions.in("c.property", properties));

 c.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);

 return c.list();

Вот некоторые примеры данных:

Parent
Parent ID
A
B
C

Children
Child ID    Parent ID   property
...         A           0
...         A           2
...         A           7
...         B           1
...         C           1
...         C           2
...         C           3

Я хочу вернуть родителей и ВСЕХ их детей, если у одного из детей естьсвойство, равное моим параметрам привязки.Предположим, что свойства - это массив, содержащий {2}.В этом случае вызов вернет родителей A и C, но их дочерние коллекции будут содержать только элемент 2. Т.е. Parent [Children]:

A [2] & C [2]

ЧтоЯ хочу это:

A [0, 2, 7] & C [1, 2 3]

Если это не ошибка, это кажется нарушенной семантикой.Я не понимаю, как вызов A.getChildren () или C.getChildren () и возвращение 1 записи когда-либо считался бы правильным - это не проекция.Т.е. если я увеличу запрос, чтобы использовать выборку по умолчанию, он вернет нужные дочерние коллекции, albiet с множеством запросов:

  c.createAlias("children", "c").add(
      Restrictions.in("c.property", properties));

Это ошибка?Если нет, как я могу достичь желаемого результата?

Ответы [ 4 ]

5 голосов
/ 30 марта 2014
        Criteria c = session.createCriteria(Parent.class);

    c.createAlias("children", "children");
    c.add(Restrictions.in("children.property", properties));

     c.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);

     return c.list();
1 голос
/ 10 августа 2011

getChildren () - это просто имя получателя / установщика, ваш запрос определит, как объекты будут заполнены.

Я собираюсь догадаться, что первая часть выплевывает

SELECT * FROM Parent 
INNER JOIN Child c ON ... 
WHERE c.property in (x,y,z) 

, который не дает вам то, что вы хотите.Что бы вы хотели сделать, если бы писали это на необработанном SQL, вот что:

SELECT * FROM Parent  
WHERE ParentID IN (SELECT DISTINCT parentID FROM Child WHERE  c.property in (x,y,z))

надлежащая перестановка ваших критериев может помочь, если последний не производит этот запрос.(Не могли бы вы также опубликовать, что hibernate генерирует для каждого?)

0 голосов
/ 02 июля 2015

Это можно сделать обходным путем.

Criteria c1 = session.createCriteria(Child.class);
c1.add(Restrictions.in("property", properties));
c1.setProjection( Projections.distinct( Projections.property( "parentId" ) ) );
List<Integer> parentIds = c1.list();

Criteria c2 = session.createCriteria(Parent.class);
c2.createAlias("children", "children");
c2.add(Restrictions.in("id", parentIds));
return c2.list();
0 голосов
/ 02 апреля 2013

Я бы начал Критерии с дочернего класса. Вы получите список со всеми дочерними элементами, а затем сможете выполнить итерацию и получить родителей для каждого дочернего элемента.

...