2011-10-07 8 views
8
私は次のエンティティを持っています

コレクションテーブルのHibernate criteriaクエリ?

@Entity 
@Table(name = "rule") 
public class Rule implements Serializable { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    @Column(name = "rule_id") 
    private Long id; 

    @ElementCollection(targetClass = Action.class) 


    @CollectionTable(name = "rule_action", joinColumns = @JoinColumn(name = "rule_id")) 
     @Enumerated(value = EnumType.STRING) 
     @Column(name = "action") 
     private Set<Action> actions; 

//After editing as per jbrookover's suggestion adding a new mapping 
     @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY) 
     @JoinColumn(name = "rule_id") 
     private Set<RuleAction> ruleActions; 


    } 
次は私のアクションです

public enum Action { 
    PHONE, EMAIL, POSTAL,PHONE_OR_EMAIL, SMS; 
} 

特定のアクションセットを持つルールのリストを表示したい これを試しています

 DetachedCriteria criteria = DetachedCriteria.forClass(Rule.class,"rule"); 
criteria = criteria.createAlias("rule.actions", "action"); 
criteria.add(Restrictions.in("action.name",actionSet)); 
return getHibernateTemplate().findByCriteria(criteria); 

org.hibernate.MappingException:コレクションは関連付けではありません。例外..

EDIT したがって、jbrookoverからのガイダンスの後、RuleActionという名前のActionのラッパークラスを試してみました。そしてoneToManyをeshtablishできました関係、また私は次のようにクエリを変更しました。

 Set<Action> act = new HashSet<Action>(); 
    act.add(Action.EMAIL); 
    act.add(Action.POSTAL); 

    DetachedCriteria criteria = DetachedCriteria.forClass(Rule.class); 
    criteria.add(Restrictions.eq(SUPPORT_LANG, Language.valueOf("EN"))) 
      .createCriteria("ruleActions").add(Restrictions.in("action",act)); 
    return getHibernateTemplate().findByCriteria(criteria); 

しかし、これはEMAILまたはPOSTALのいずれかを持つすべてのルールを返しますが、私が望むのはです。クエリを変更します。

答えて

6

申し訳ありませんが、具体的には、Hibernateではサポートされていません。このFAQを参照してください。

http://community.jboss.org/wiki/HibernateFAQ-AdvancedProblems#Im_getting_orghibernateMappingException_collection_was_not_an_association_when_I_try_to_join_a_collection_of_components_with_Criteria_queries

私は、あまりにも、これと非常に不快でした。あなたが見ることができるように、彼らはそうすることができなかったそれを修正しようとし、それを処理するためにそれをコミュニティに置いた。いくつかのオプションがあります:

  1. HQLを使用してクエリを実行します。
  2. コレクションの関連付けを、実際のエンティティクラスとして単一のEnumフィールドで書き換えます。 、そして、

    @Entity 
    public class ActionWrapper { 
    
         public Action action; 
    } 
    

    RuleSet<ActionWrapper>を持つようにそれに応じて団体やクエリを更新:

あなたはこのような何かを行うことができます。その他の回避策がありますが、基本的にCriteria@ElementCollectionを一緒に使用することはできません。 「と」 - - 一致した値の

更新

あなたは両方のアクションを満たすルールを得ることを保証するために、さらにクエリを制限するためには、サブクエリを実行して、一緒に行う必要があります。このようなものはうまくいくはずです:

Criteria subCriteria = criteria.createCriteria("ruleActions"); 
Disjunction and = Restrictions.conjunction(); 
for (Action a : act) 
    and.add(Restrictions.eq("action", a) 
subCriteria.add(and); 

最後に、結果が重複していることがあります。これは一般的であり、これを追加することで解消することができます。

criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); 

私はこのコードの効率化のために話すことができない - HQLは、長期的には良いかもしれません。しかし、私は他のプロジェクトでも同様のことをしてきましたが、問題は発生していません。

 @ElementCollection(fetch = FetchType.EAGER) 
     @Enumerated(value = EnumType.STRING) 
     @Column(name = " action") 
     @JoinTable(name = "rule_action", joinColumns = { @JoinColumn(name = "rule_id") }) 
     private Set<Action> actions; 

クエリ:休止4.1.6.Finalと私のために働いたものだ

DetachedCriteria criteria = DetachedCriteria.forClass(Rule.class,"rule"); 
criteria = criteria.createAlias("rule.actions", "action"); 
criteria.add(Restrictions.in("action." + CollectionPropertyNames.COLLECTION_ELEMENTS, actionSet)); 
return getHibernateTemplate().findByCriteria(criteria); 

+0

hi jbrookover ..thanks !!私はラッパークラスを進めようとしています。私が行っていることに応じてあなたの答えを変更しました。同じ問題に直面する可能性のある他の人を助けるかもしれません。 –

+0

@AnupamGupta制限付きクエリを含むように更新されました。 – jbrookover

+0

おかげさまで@jbrookover今のところ私はHql..andを使い、あなたの提案に応じてすぐにあなたの提案を変更しますので、ここで更新する予定ですので、他の人にとって参考になるかもしれません –

1

条件クエリが正常に表示されます。私たちはテーブルがあるとします。

rule(id, name,...) 
action(id, name,..) 
rule_action(id, rule_id, action_id,...) -- (or rule_id+action_id as a composite pkey) 

次のようにマッピングは次のようになります。

public class Rule { 
    ... 
    @ManyToMany(mappedBy = "rule") 
    private Set<Action> actions; 
    ... 
} 

public class Action { 
    ... 
    @JoinTable(
     name="rule_action", 
     joinColumns={@JoinColumn(name="action_id")}, 
     inverseJoinColumns={@JoinColumn(name="rule_id")} 
    ) 
    private Set<Rule> rules; 
    ... 
} 

あなたの基準のクエリが動作するはずです。この方法で。

+0

こんにちは、上記の場合の休止状態のクエリを書く方法を教えてください。私のクエリがアクションAとDを持つすべてのルールを返すような基準を追加したいのですが、 B、C、D、E}) –

+0

こんにちは、ごめんなさい。最初の答えは全く誤解を招いていたので、私は完全に書き直しました。見てみましょう。 – forker

+0

実際には、現在のコードでCollectionTableが使用されているので、マッピングを変更することに心配しています。現在のマッピングは広範囲に使用されているので、既存のコードを壊していないことを確認したいだけです。あなたが言ったようなマッピングを変更すると、既存のシステムに影響が出ますか? –

3

あなたの列挙型をラップしてResultTransformersを使用せずに別の解決策はこれです。私はそれを見つけたhere

+0

私! – George

関連する問題