2011-01-29 4 views
12

私は、Hibernateを使用して複雑なクエリをまとめようとしています。私はCriteriaに傾いていますが、それは不可能であると思われ始めています。したがって、どんな提案も役立つでしょう。コレクションの値のHibernateの基準

私は、次のようなエンティティの構造を有する:

public class Attribute { 
    private Integer id; 
    private String name; 
    private Set<Value> values; 
} 

public class Instance { 
    private Integer id; 
    private int instanceRef; 
    private Set<Value> values; 
} 

public class Value { 
    private Integer id; 
    private Attribute attribute; 
    private String localAttributeName; 
    private Instance instance; 
    private String value; 
} 

これらのエンティティは、あなたが期待するよう関連しています

value.attribute_id --> attribute.id 
value.instance_id --> instance.id 

を今、私はセットを取ることができるようにしたいと思います属性/値のペア(文字列)を検索し、すべてを含むすべてのインスタンスを見つけます。 Valueでは、attributeおよびlocalAttributeNameのいずれか1つのみがnullでないため、属性名はlocalAttributeNameまたはattribute.nameと一致します。最後に、値のユニークなインデックス(インスタンス、属性、値)または(インスタンス、localAttributeName、値)を複雑にする - インスタンス内では、任意の属性は複数の値を持つことがあります。

これは私がこれまで持っているものです。

public List<Instance> getMatchingInstances(Map<String, String> attrValues) { 
    Criteria crit = session.createCriteria(Instance.class, "i"); 
    for(Map.Entry<String, String> entry : attrValues) { 
     DetachedCriteria valueCrit = DetachedCriteria.forClass(Value.class, "v"); 

     // Do something here with valueCrit 

     crit.add(Subqueries.exists(valueCrit)); 
    } 
    return crit.list(); 
} 

私がやった研究に基づいて、私はそのために試したどの部分が何か操作を行います。

// This would only check localAttributeName and not attribute.name. 
    // That's okay -- once I get the rest to work, I can figure this out. 
    valueCrit.add(Restrictions.eq("localAttributeName", entry.getKey()); 
    valueCrit.add(Restrictions.eq("value", entry.getValue()); 
    valueCrit.add(Restrictions.eqProperty("v.instance_id", "i.id")); 

しかし、これはスローを私がCriteriaでこれを行うことはできないと私は思っていますが、それ以外は学ぶことが大好きです。これを行う最善の方法は何でしょうか?

答えて

17

私は数時間後に解決策を見つけました。うまくいけば、これは他人に役立つものです。

  1. 適切に
  2. が正しく主な基準

Iに戻ってサブクエリをマップ結合を作成

  • を投影を追加します。私はこれが実現可能にするために解決するために必要な3つの主な点がありました以下のコードでこれらのそれぞれを強調表示しています。

    最初に、例外を取り除くために、サブクエリには下に強調表示されている投影が必要であることがわかりました。私はちょうどInstanceの "id"プロパティの投影をしました。

    次に、結合を取得するために、Criteria.createCriteria()メソッドを使用して、左外部結合を作成しました。さまざまなレベルの参加条件で複数の条件があったため、参加した条件を保存して別々に表現を添付する必要がありました。これにより、サブクエリでOR式を実行できます。

    最後に、サブクエリをメインの基準に戻すためにeqProperty()句を追加する必要がありました。 SQLの結果と同じように、私はinstance.id = i.idを使用しました。インスタンスの基準をすでに「i」にマップしていて、この句を値の基準に追加していたので、これがSQLに変換されました:v.instance_id = i.id.

    はここで動作するコードです:

    public List<Instance> getMatchingInstances(Map<String, String> attrValues) { 
        Criteria crit = session.createCriteria(Instance.class, "i"); 
        for(Map.Entry<String, String> entry : attrValues) { 
         String attrName = entry.getKey(); 
         String val = entry.getValue(); 
    
         // Create the subquery 
         DetachedCriteria valueCrit = DetachedCriteria.forClass(Value.class, "v"); 
    
         // Join the Attribute object (left outer join) 
         DetachedCriteria attrCrit = 
          valueCrit.createCriteria("attribute", CriteriaSpecification.LEFT_JOIN); 
    
         // Put together the OR statement on the Attribute joined criterion. 
         Criterion localAttr = Restrictions.eq("v.localAttributeName", attrName); 
         Criterion globalAttr = Restrictions.eq("name", attrName); 
         attrCrit.add(Restrictions.or(localAttr, globalAttr)); 
    
         // Simple column equality on the subquery criterion. 
         valueCrit.add(Restrictions.eq("value", val)); 
    
         // Map the subquery back to the outer query. 
         valueCrit.add(Restrictions.eqProperty("instance.id", "i.id")); 
    
         // Add the missing projection. 
         valueCrit.setProjection(Projections.property("id")); 
    
         // Add this subquery to the outer query. 
         crit.add(Subqueries.exists(valueCrit)); 
        } 
        return crit.list(); 
    } 
    
  • +1

    それは動作します!!! ...ありがとう。 – Gaurav

    +0

    ちょっと@ジョン、この問題を手伝ってくれますか?リンクはhttp://stackoverflow.com/questions/22919886/hibernate-criteria-filtering-by-attributes-of-collectionです。ありがとう!何かについてはかなり似ています! – Victor

    +0

    この回答はHibernateのどのバージョンに適していますか? –