是否有可能获得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

尝试创建另一个标准

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