Можно ли получить псевдоним SQL таблицы соединений для Hibernate sqlRestriction?

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

@Entity
class Person {

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

Hibernate создает две таблицы в моей базе данных Person и Person_aliases. Person_aliases - это таблица соединений с столбцами Person_id и element. Пусть say 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? Если нет подходящего токена подстановки, такого как {alias}, то есть ли способ заставить спящий режим сказать мне, что это за псевдоним? Я заметил метод, называемый классом generateAlias ​​() org.hibernate.util.StringHelper. Помогло бы мне предсказать, что такое псевдоним?

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

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

Ответ 1

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

from Person p where :alias in elements(p.aliases)

Ответ 2

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

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

вам нужно:

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

Это позволило решить подобные проблемы для меня, не перейдя на HQL

Ответ 4

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

Criteria crit = session.createCriteria(Person.class, "person");
Criteria subC = crit.createCriteria("Person_aliases", "Person_aliases");
subC.add(Restrictions.sqlRestriction("{alias}.element='superman'");

Ответ 5

May эта ссылка поможет вам? Он советует:

List persons = sess.createCriteria(Person.class)
       .createCriteria("company")
       .add(Restrictions.sqlRestriction("companyName || name like (?)",  "%Fritz%", Hibernate.STRING))
       .list(); 

Ответ 6

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

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

Вот код класса 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 restriciton и передать его в контейнер.

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));

Ответ 7

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

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

Ответ 8

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")));