Можно ли получить псевдоним SQL таблицы соединений для Hibernate sqlRestriction? - PullRequest
12 голосов
/ 27 февраля 2010

У меня есть класс Person, у которого есть коллекция псевдонимов String, представляющая дополнительные имена, которые может пройти этот человек. Например, у Кларка Кента могут быть псевдонимы «Супермен» и «Человек из стали». Дуайт Ховард также имеет псевдоним "Супермен".

@Entity
class Person {

  @CollectionOfElements(fetch=FetchType.EAGER)
  Set<String> aliases = new TreeSet<String>();

Hibernate создает две таблицы в моей базе данных, Person и Person_aliases. Person_aliases - это объединяющая таблица со столбцами Person_id и element. Допустим, Person_aliases имеет следующие данные

--------------------------------
| Person_id     | element      |
--------------------------------
| Clark Kent    | Superman     |
| Clark Kent    | Man of Steel |
| Dwight Howard | Superman     |
| Bruce Wayne   | Batman       |
--------------------------------

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

По причинам, слишком длинным для перечисления здесь, я действительно хотел бы сделать это запросом Criteria, а не HQL-запросом (если только невозможно добавить ограничение HQL для объекта Criteria, в этом случае я весь слух) или сырой запрос SQL. Поскольку в соответствии с Как запросить объекты со значением в коллекции String с использованием Hibernate Criteria? невозможно ссылаться на элементы коллекций типа значения с помощью CriteriaAPI. Я подумал, что прибегну к добавлению SqlRestriction на моем объекте критериев.

Criteria crit = session.createCriteria(Person.class);
crit.add(Restrictions.sqlRestriction("XXXXX.element='superman'");

в надежде, что Hibernate создаст оператор SQL, такой как

    select *
from
    Person this_ 
left outer join
    Person_aliases aliases2_ 
        on this_.id=aliases2_.Person_id 
where
    XXXXX.element='superman' 

Однако мне нужно заполнить XXXXX псевдонимом таблицы для таблицы Person_aliases в SQL-запросе, который в этом случае будет «aliases2_». Я заметил, что если бы мне понадобилась ссылка на псевдоним таблицы Person, я мог бы использовать {alias}. Но это не сработает, потому что Person является основной таблицей для этого критерия, а не Person_aliases.

Что мне заполнить для XXXXX? Если нет подходящего токена подстановки, такого как {псевдоним}, то есть ли способ перевести меня в спящий режим, чтобы сказать мне, каким будет этот псевдоним? Я заметил метод с именем generateAlias ​​() org.hibernate.util.StringHelper class. Поможет ли это мне предсказать, каким будет псевдоним?

Я бы очень, очень хотел бы избежать жесткого кодирования 'aliases2_'.

Спасибо за ваше время!

Ответы [ 8 ]

9 голосов
/ 03 августа 2011

как намекает xmedeko, когда вы хотите сделать:

crit.add(Restrictions.sqlRestriction(
    "{alias}.joinedEntity.property='something'"));

вам нужно вместо этого сделать:

crit.createCriteria("joinedEntity").add(Restrictions.sqlRestriction(
    "{alias}.property='something'"));

Это решило подобные проблемы для меня, не переходя на HQL

4 голосов
/ 27 февраля 2010

Похоже, что Criteria API не позволяет запрашивать коллекции элементов, см. HHH-869 (который все еще открыт). Так что либо попробуйте предложенный обходной путь - я этого не сделал - либо переключитесь на HQL. Следующий HQL-запрос будет работать:

from Person p where :alias in elements(p.aliases)
3 голосов
/ 30 июня 2014

попробуйте создать еще один критерий, например

Criteria crit = session.createCriteria(Person.class, "person");
Criteria subC = crit.createCriteria("Person_aliases", "Person_aliases");
subC.add(Restrictions.sqlRestriction("{alias}.element='superman'");
3 голосов
/ 20 августа 2010

Просмотрите ошибки Hibernate и используйте прикрепленные файлы:

2 голосов
/ 20 августа 2010

Может эта ссылка Вам помочь? Советы:

List persons = sess.createCriteria(Person.class)
       .createCriteria("company")
       .add(Restrictions.sqlRestriction("companyName || name like (?)",  "%Fritz%", Hibernate.STRING))
       .list(); 
1 голос
/ 15 октября 2013

Вопрос на самом деле довольно старый, но поскольку сегодня я столкнулся с той же проблемой, и ни один ответ не удовлетворил мои потребности, я предложил следующее решение, основанное на комментарии *1002* Бретта Мейера HHH-6353 , что эти проблемы не будут исправлены.

По сути, я расширил класс SQLCriterion , чтобы иметь возможность обрабатывать больше, чем псевдоним базовой таблицы. По соображениям удобства я написал небольшой контейнерный класс, который связывает данный псевдоним пользователя с соответствующим экземпляром подкритерия, чтобы иметь возможность заменить данный псевдоним пользователя на псевдоним hibernate, созданный для подкритериев.

Вот код класса MultipleAliasSQLCriterion

public class MultipleAliasSQLCriterion extends SQLCriterion
{
    /**
     * Convenience container class to pack the info necessary to replace the alias      generated at construction time
     * with the alias generated by hibernate
     */
    public static final class SubCriteriaAliasContainer
    {
        /** The alias assigned at construction time */
        private String alias;

        /** The criteria constructed with the specified alias */
        private Criteria subCriteria;

        /**
         * @param aAlias
         *            - the alias assigned by criteria construction time
         * @param aSubCriteria
         *            - the criteria
         */
        public SubCriteriaAliasContainer(final String aAlias, final Criteria aSubCriteria)
        {
            this.alias = aAlias;
            this.subCriteria = aSubCriteria;
        }

        /**
         * @return String - the alias
         */
        public String getAlias()
        {
            return this.alias;
        }

        /**
         * @return Criteria - the criteria
         */
        public Criteria getSubCriteria()
        {
            return this.subCriteria;
        }
    }

    private final SubCriteriaAliasContainer[] subCriteriaAliases;

    /**
     * This method constructs a new native SQL restriction with support for multiple aliases
     * 
     * @param sql
     *            - the native SQL restriction
     * @param aSubCriteriaAliases
     *            - the aliases
     */
    public MultipleAliasSQLCriterion(final String sql, final SubCriteriaAliasContainer... aSubCriteriaAliases)
    {
        super(sql, ArrayHelper.EMPTY_OBJECT_ARRAY, ArrayHelper.EMPTY_TYPE_ARRAY);

        this.subCriteriaAliases = aSubCriteriaAliases;
    }

    @Override
    public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException
    {
        // First replace the alias of the base table {alias}
        String sql = super.toSqlString(criteria, criteriaQuery);

        if (!ArrayUtils.isEmpty(this.subCriteriaAliases))
        {
            for (final SubCriteriaAliasContainer subCriteriaAlias : this.subCriteriaAliases)
            {
                sql = StringHelper.replace(sql, subCriteriaAlias.getAlias(), criteriaQuery.getSQLAlias(subCriteriaAlias.getSubCriteria()));
            }
        }

        return sql;
    }
}

Я использую это так

final String sqlRestriction = "...";
final String bankAccountAlias = "ba";
final Criteria bankAccountCriteria = customerCriteria.createCriteria("bankAccount", bankAccountAlias);

SubCriteriaAliasContainer bankAccountSubAliasCon = new SubCriteriaAliasContainer(bankAccountAlias, bankAccountCriteria);        

customerCriteria.add(new MultipleAliasSQLCriterion(sqlRestriction, bankAccountSubAliasCon));

Но нет необходимости указывать псевдоним при создании критериев - вы также можете указать его в ограничении SQL и передать его в контейнер.

final String sqlRestriction = "... VALUES(ba.status_date), (ba.account_number) ...";
final Criteria bankAccountCriteria = customerCriteria.createCriteria("bankAccount");

SubCriteriaAliasContainer bankAccountSubAliasCon = new SubCriteriaAliasContainer("ba", bankAccountCriteria);        

customerCriteria.add(new MultipleAliasSQLCriterion(sqlRestriction, bankAccountSubAliasCon));
0 голосов
/ 11 января 2017

org.hibernate.criterion.CriteriaQuery имеет метод getColumnsUsingProjection, который дает псевдоним столбца.

Вы можете реализовать свой собственный Criterion, используя org.hibernate.criterion.PropertyExpression в качестве примера.

0 голосов
/ 30 октября 2010
public class Products {
private Brands brand;
...
}
public class Brands {
private long id;
...
}
...

DetachedCriteria dc=DetachedCriteria.forClass(Products.class, "prod");

dc.add(Restrictions.ge("prod.brand.id", Long.parseLong("12345")));
...