1

DetachedCriteria で選択しようとしています。実行時に OR で区切られたいくつかの条件を追加したいと考えています。

私が使用する場合:

Restrictions.Or( cond1, Restrictions.Or(cond2, Restrictions.Or(cond3, cond4)) )

欲しい結果が得られます。

しかし、次のように Disjunction を使用すると:

var disjunction = Restrictions.Disjunction();
disjunction.Add(cond1);
disjunction.Add(cond2);
disjunction.Add(cond3);
disjunction.Add(cond4);

そして、cond1 と cond2 が true であるエンティティがあり、結果でそれらを 2 回取得します (リストの結果では、まったく同じエンティティが 2 回返されます)。

QueryOver では難しいことを達成しようとしているため、QueryOver を使用したくありません (私がやろうとしていることの最終結果は、フィルターの json から SQL クエリを取得することです)。

論理和が double を返す原因は何ですか? 最後に DISTINCT を追加する方法はありますか? 私はそれを間違っていますか?同じテーブルの異なる条件に論理和を使用すべきではありませんか?

アップデート:

DISTINCT 部分の場合:

criteria.SetResultTransformer(new NHibernate.Transform.DistinctRootEntityResultTransformer());

また

Projections.Distinct(Projections.Id())

実際の解決策は、Radim Köhlerが述べているとおりです- The correct use of a sub query.

4

1 に答える 1

3

ちょっとした言い訳: 質問はマッピングを提供しません。クエリも欠落しています...したがって、何が問題なのかを推測することしかできません。しかし、いくつかの説明を提供しようとしましょう

なぜ受信が明確ではないのですか?

2つのテーブルを用意しましょう(質問の下のコメントの1つに示されているように)

親:

ParentId | Name
1        | Parent_A
2        | Parent_B

子:

ChildId | Color | ParentId
1       | green | 1
2       | grey  | 1
3       | gold  | 1
4       | green | 2

純粋なSQLで単純な選択を作成する場合、これを持っています

SELECT p.ParentId, p.Name
FROM Parent AS p
  INNER JOIN Child AS c
    ON p.ParentId = c.ParentId
WHERE 
  c.Color = 'green' OR c.Color = 'grey' OR c.Color = 'gold'

このクエリの結果はどうなりますか?

1 | Parent_A
1 | Parent_A
1 | Parent_A
2 | Parent_B

それを同様の基準に変換すると、次のようになります。

var sesion = ... // get session 

var parent = sesion.CreateCriteria<Parent>();

var children = parent.CreateCriteria("Children");

// restrict the children
children.Add(Restrictions.Disjunction()
    .Add(Restrictions.Eq("Color", "green"))
    .Add(Restrictions.Eq("Color", "grey"))
    .Add(Restrictions.Eq("Color", "gold"))
    );

var list = parent
    .SetMaxResults(10) // does not matter in our example, but ... it should be used always
    .List<Parent>();

これは Criteria C# コードで、結果として複数の親が生成されます (上記のように同じ SQL が生成されるという事実のため)。

ご覧のとおり、問題は明らかに NHiberante 側にあるわけではありません。本当!Hibernate は無害であるだけでなく、必要なことも実行します。

解決

解決策はサブセレクトにあります

SQLでは、このようになります

SELECT p.ParentId, p.Name
FROM Parent AS p
WHERE p.ParentId IN (
  SELECT c.ParentId
  FROM Child AS c
    WHERE c.ParentId = p.ParentId
    AND c.Color = 'green' OR c.Color = 'grey' OR c.Color = 'gold'
)

これにより、最も望ましい結果が得られます。

1 | Parent_A
2 | Parent_B

そして、NHibernateでそれを行う方法は?

var sesion = ... // get session 

var parent = sesion.CreateCriteria<Parent>();

//var children = parent.CreateCriteria("Children");
var children = DetachedCriteria.For(typeof(Child));

// restrict the children
children.Add(Restrictions.Disjunction()
    .Add(Restrictions.Eq("Color", "green"))
    .Add(Restrictions.Eq("Color", "grey"))
    .Add(Restrictions.Eq("Color", "gold"))
    );

// ad SELECT into this sub-select
children.SetProjection( Projections.Property("ParentId"));

// filter the parent
parent
    .Add(Subqueries.PropertyIn("ParentId", children));


var list = parent
    .SetMaxResults(10) // does not matter in our example, but ... it should be used always
    .List<Parent>();

現在、サブセレクト (DetachedCriteriaおよびSubqueriesNHibernate 機能) があり、重複はありません!

于 2013-05-18T15:24:35.987 に答える