Запрос отношений ManyToMany с Hibernate Criteria - PullRequest
10 голосов
/ 05 ноября 2008

Я не уверен, как описать эту проблему, поэтому я думаю, что пример - лучший способ задать мой вопрос:

У меня есть две таблицы с отношением manyToMany:

DriversLicence <-> LicenceClass

LicenceClass - это такие вещи, как "Автомобиль", "Мотоцикл" и "Средняя жесткость".

Как использовать Hibernate Criteria, как найти все лицензии, имеющие классы Licence "Car" и "Motorbike"?

ОБНОВЛЕНИЕ 12/11/2008 Я обнаружил, что это может быть легко достигнуто с помощью пользовательского ResultTransformer. Однако проблема в том, что преобразователь результатов применяется только ПОСЛЕ того, как запрос возвращает свои результаты, он фактически не становится частью SQL. Итак, я думаю, что мой вопрос теперь «Можете ли вы сделать то, что я первоначально описал в SQL - и есть ли аналог Hibernate Criteria?»

Ответы [ 5 ]

6 голосов
/ 24 ноября 2008

Вот как я наконец добился этого с помощью HQL:

public List<DriversLicence> findDriversLicencesWith(List<LicenceClass> licenceClasses) {
    String hqlString = "select dl from DriversLicenceImpl dl where 1=1 ";
    for (int i = 0; i < licenceClasses.size(); i++) {
        hqlString += " and :licenceClass" + i + " = some elements(dl.licenceClasses)";
    }

    Query query = getSession().createQuery(hqlString);
    for (int i = 0; i < licenceClasses.size(); i++) {
        query.setParameter("licenceClass" + i, licenceClasses.get(i));
    }
    return query.list();
}

Или используя Критерии гибернации с ограничением sql:

for (LicenceClass licenceClass : licenceClasses) {               
    criteria.add(Restrictions.sqlRestriction("? = some(select " + LicenceClass.PRIMARY_KEY + " from " +
                    LICENCE_CLASS_JOIN_TABLE + "  where {alias}." +
                    DriversLicence.PRIMARY_KEY + " = " + DriversLicence.PRIMARY_KEY + ")",
                    licenceClass.getId(), Hibernate.LONG));
}

LICENCE_CLASS_JOIN_TABLE - это имя таблицы, которую генерирует hibernate для поддержки отношения «многие ко многим» между driversLicence и LicenceClass.

0 голосов
/ 04 октября 2016

Другим вариантом является объединение цепочек (по одному соединению на каждый LicenseClass). Я использовал построитель критериев и такие предикаты

 List<Predicate> predicates = new ArrayList<>();
 for(Integer lcId : licenceClassIdList) {
     SetJoin<DriversLicence, LicenceClass> dlClasses = dlRoot.join(DriversLicence_.licenceClasses);
     predicates.add(builder.equal(dlClasses.get(LicenseClass_.id), lcId));
 }
 Predicate predicate = builder.and(predicates.toArray(new Predicate[predicates.size()]));

Обратите внимание, что dlRoot является объектом класса Root, и вы можете получить его из класса CriteriaQuery. Полученный предикат - это то, что вы ищете ...

0 голосов
/ 07 ноября 2008

'Я не думаю, что это сработает. Я хочу найти все лицензии, которые имеют и"Автомобиль" и "Мотоцикл" '

Пользовательский Expression.and (....) вместо Expression.or (....) в фрагменте, предоставленном Ником

0 голосов
/ 12 ноября 2008

У меня была похожая проблема, но она была исправлена ​​с помощью HQL, у меня есть класс «Enterprise», который связан с классом «User», а также с классом «Role», они связывают многие со многими, когда мне нужно все предприятия, связанные с конкретным пользователем, я делаю следующее;

Select e from Enterprise As e inner join e.Users As u inner join u.Roles As r 
Where u.UserCode=?

Полагаю, в вашем случае вы должны сделать что-то вроде:

Select dl from LicenceClass As l inner join l.DriversLicences As dl
Where 
l.LicenseClass.Name = ? OR 
l.LicenseClass.Name=? OR 
l.LicenseClass.Name=?

Надеюсь, это поможет.

0 голосов
/ 05 ноября 2008

Вы все еще можете использовать точечную нотацию для работы через отношения. Например, если у вас есть свойство DriversLicence.licenceClass и свойство LicenceClass.type, то:

session.createCriteria(DriversLicence.class)
   .add(Expression.or(
     Expression.eq("licenceClass.type", "Car"),
     Expression.eq("licenceClass.type", "Motorbike")
   )
).list();

Лично я бы просто не использовал критерии в этом случае, потому что это не динамический запрос, а вместо этого использовал бы:

session.createQuery("from DriversLicence where licenceClass.type in (:types)")
  .setParameterList("types", myListOfTypes)
  .list();
...