2010-02-26 49 views
12

我有一個人類有一個字符串集合的別名代表人可能會經過的額外名稱。例如,克拉克肯特可能會有別名「超人」和「鋼鐵俠」。德懷特霍華德也有一個「超人」的別名。是否有可能爲Hibernate sqlRestriction獲取連接表的SQL別名?

@Entity 
class Person { 

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

Hibernate在我的數據庫Person和Person_aliases中創建了兩個表。 Person_aliases是一個包含Person_id和元素的連接表。比方說,Person_aliases具有以下數據

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

我想爲誰是「超人」的別名全力以赴的人休眠條件查詢。

由於在這裏列出的原因太長,我真的希望將此作爲Criteria查詢,而不是HQL查詢(除非可以在Criteria對象上添加HQL限制,在這種情況下,我全是耳朵)或原始SQL查詢。由於根據How do I query for objects with a value in a String collection using Hibernate Criteria?,使用CriteriaAPI引用值類型集合的元素是不可能的,我想我會在我的criteria對象上添加一個SqlRestriction。

Criteria crit = session.createCriteria(Person.class); 
crit.add(Restrictions.sqlRestriction("XXXXX.element='superman'"); 
在Hibernate會創建一個像

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

但是SQL語句的希望

,我需要填寫XXXXX在SQL查詢表別名Person_aliases表,在這個情況會是'aliases2_'。我注意到,如果我需要引用Person表別名,我可以使用{別名}。但是這不起作用,因爲Person是這個標準的主要表格,而不是Person_aliases。

我爲XXXXX填寫什麼?如果沒有像{alias}這樣好的替換標記,那麼是否有辦法讓hibernate告訴我該別名會是什麼?我注意到了一個名爲generateAlias()org.hibernate.util.StringHelper類的方法。這會幫助我預測別名會是什麼?

我真的很想避免硬編碼'aliases2_'。

謝謝你的時間!

回答

4

似乎Criteria API不允許查詢元素的集合,請參閱HHH-869(它仍處於打開狀態)。所以要麼嘗試建議的解決方法 - 我沒有 - 或切換到HQL。以下HQL查詢將起作用:

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

感謝您的回覆 - 實際上,由於之前的堆棧溢出問題,我確實知道不幸的Criteria API限制,但希望通過sqlRestriction使用本機SQL代碼段可能會提供一個「黑客」,讓我們仍然使用Criteria。但我找不到一種方法來獲取對連接表名稱的引用。如果沒有辦法,我會像你所建議的那樣訴諸HQL。然而,有些理由我不想要這將需要更多的空間比我在這裏解釋(這個問題是我們的實際查詢的簡化表示) – 2010-03-01 17:14:25

+0

@Jason也許這是可能的,但*我*看不到如何沒有硬編碼表名。 – 2010-03-01 17:20:28

2

5月this link可以幫到您嗎?它建議:

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

爲主類上的連接對象調用createCriteria()方法解決了我的問題。我在連接對象的類的子條件中添加了所有連接字段,並解決了我的問題。 – 2014-07-16 12:33:21

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

爲xmedeko暗指,當你想要做的:

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

你需要,而不是做:

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

這解決了我類似的問題,而不去HQL

+0

我應該使用實際的字符串「{別名}」還是用'accountUser'這樣的對象名替換它? – NobleUplift 2016-07-13 20:05:51

+1

使用字符串{別名}它是一個hibernate關鍵字,不幸的是它是在標準世界中使用別名的唯一方法。 – pstanton 2016-07-14 04:28:30

+0

這工作正常,但我找不到與此相關的文檔。你知道嗎? – 2016-07-27 05:32:46

1

的問題其實是很老,但因爲我遇到了同樣的問題,今天,沒有回答滿足我的需求,我想出了以下解決方案,基於Brett Meyer的commentHHH-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

謝謝,這很有幫助! – Ben 2015-09-30 17:53:23

+0

我不知道你的例子中是否有兩個錯別字。 bankAccountSubAliasCon對象是不是應該傳遞給MultipleAliasSQLCriterion構造函數? – Stephane 2016-03-22 07:39:48

+0

下面是我用你的實用程序:'hibernatePersonAlias =「p」; Criteria personCriteria = mainCriteria.createCriteria(「person」,hibernatePersonAlias); String personSalarySqlCriterion = hibernatePersonAlias +「.salary> 1500」; MultipleAliasSQLCriterion.SubCriteriaAliasContainer personAliasContainer = new MultipleAliasSQLCriterion.SubCriteriaAliasContainer(hibernatePersonAlias,personCriteria); mainCriteria.add(new MultipleAliasSQLCriterion(personSalarySqlCriterion,personAliasContainer));' – Stephane 2016-03-22 09:35:02

3

嘗試創建另一個標準像

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

org.hibernate.criterion.CriteriaQuery有一個方法getColumnsUsingProjection,讓你的別名的列名。

您可以實施自己的Criterion,以org.hibernate.criterion.PropertyExpression爲例。

相關問題