是否有可能获得Hibernate sqlRestriction的连接表的SQL别名?
我有一个Person类,它有一个别名的String集合,表示人可能经过的其他名称。 例如,克拉克肯特可能有别名“超人”和“钢铁侠”。 德怀特霍华德也有别名“超人”。
@Entity class Person { @CollectionOfElements(fetch=FetchType.EAGER) Set aliases = new TreeSet();
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 | --------------------------------
我想为所有使用“超人”别名的人制作一个hibernate Criteria查询。
由于这里列出的原因太长,我真的想把它作为Criteria查询,而不是HQL查询(除非可以在Criteria对象上添加HQL限制,在这种情况下我可以全部听到)或者是原始的SQL查询。 因为根据如何使用Hibernate Criteria在String集合中查询具有值的对象? 使用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'
但是,我需要在SQL查询中使用Person_aliases表的表别名填充XXXXX,在这种情况下,它将是’aliases2_’。 我注意到如果我需要对Person表别名的引用,我可以使用{alias}。 但这不起作用,因为Person是此Criteria的主表,而不是Person_aliases。
我要为XXXXX填写什么? 如果没有像{alias}这样的好的替代令牌,那么我有没有办法让hibernate告诉我该别名会是什么? 我注意到一个名为generateAlias()org.hibernate.util.StringHelper类的方法。 这有助于我预测别名会是什么吗?
我真的非常想避免硬编码’aliases2_’。
谢谢你的时间!
似乎Criteria API不允许查询元素集合,请参阅HHH-869 (仍然是打开的)。 所以要么尝试建议的解决方法 – 我没有 – 或切换到HQL。 以下HQL查询将起作用:
from Person p where :alias in elements(p.aliases)
正如xmedeko所暗示的那样,当你想做的时候:
crit.add(Restrictions.sqlRestriction( "{alias}.joinedEntity.property='something'"));
你需要改为:
crit.createCriteria("joinedEntity").add(Restrictions.sqlRestriction( "{alias}.property='something'"));
这样就解决了类似的问题而不需要使用HQL
看到这个Hibernate错误并使用附件:
尝试创建另一个标准
Criteria crit = session.createCriteria(Person.class, "person"); Criteria subC = crit.createCriteria("Person_aliases", "Person_aliases"); subC.add(Restrictions.sqlRestriction("{alias}.element='superman'");
愿这个链接对你有帮助吗? 它建议:
List persons = sess.createCriteria(Person.class) .createCriteria("company") .add(Restrictions.sqlRestriction("companyName || name like (?)", "%Fritz%", Hibernate.STRING)) .list();
这个问题实际上已经很老了,但由于我今天遇到了同样的问题并且没有答案满足我的需求,我根据Brett Meyer对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));
org.hibernate.criterion.CriteriaQuery
有一个方法getColumnsUsingProjection
,它为您提供别名列名。
您可以使用org.hibernate.criterion.PropertyExpression
作为示例来实现自己的Criterion
。
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")));