Можно ли получить псевдоним 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
Ответ 3
Смотрите ошибки Hibernate и используйте вложенные файлы:
Ответ 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")));