2012-03-06 13 views
3

子コレクション内のすべてのエンティティが別のリストにある親エンティティを取得しようとしています。例えばnHibernateを使用した子コレクションによるQueryOverの制限

public class Parent { 

public virtual int Id {get;set;} 
public virtual List<Child> Children {get;set;} 

} 

public class Child { 

public virtual int Id {get;set;} 
public virtual string Name {get;set;} 

} 

私が参加し、制限の様々な組み合わせを試してみたが、スポットを打つように見えることはできません。

ですので、お助けください。

下の現在の例:

public IList<Lead> GetAllAvailable(string[] names) 
    { 
     var result = Session.CreateCriteria<Parent>() 
      .CreateCriteria("Children") 
      .Add(Expression.In("Name", names)).List<Parent>(); 

     return result; 
    } 

編集:

これは、SQL equivilentです:

select * 
from dbo.Parent 
     join (select p.id 
       from  dbo.Parent p 
         join dbo.ParentToChildren on p.Id = dbo.ParentsToChildren.Parent_Id 
         join dbo.Child on dbo.ParentToChildren.Child_Id = dbo.Child.Id 
       where Name in ('foo', 'bar') 
       group by p.Id 
       having count(1) > 1 
      ) as foo on dbo.Parent.Id = foo.Id 
+0

子供たちはリストの各項目に一致する必要があります。 – shenku

+0

名前が正確にあるすべての親が必要ですか?長さの子、名前の各エントリに1つの子があります(その名前を名前として持つ)か? –

+0

これ以上は持っていないので、親は10人の子供を持つことができますが、名前リストの3つだけ一致する必要があります。良いことだ – shenku

答えて

3

ここに私の提案です:

var parents = session.QueryOver<Child>() 
    .WhereRestrictionOn(x => x.Name).IsIn(names) 
    .Select(Projections.Group<Child>(x => x.Parent)) 
    .Where(Restrictions.Ge(Projections.Count<Child>(x => x.Parent), names.Length)) 
    .List<Parent>(); 

次のようにアイデアがあります:すべての子供を見つけるそれらはnamesのエントリの1つのようなNameを持っています。それらの子供をグループ化する。ParentChildには、それぞれの親にマップされたParentプロパティが必要ですが、とにかくそれは良い考えです。同じサイズ(またはそれ以上)のグループすべてについて、GeEqに置き換えることができるように、names.Lengthを返す。グループのサイズがnames.Lengthに等しい場合、すべての名前はであり、親の2人の子供が同じ名前のを持たないと仮定されているためです。

生成されたクエリ:

SELECT 
    this_.Parent as y0_ 
FROM 
    Child this_ 
WHERE 
    this_.Name in (
     /* */ 
    ) 
GROUP BY 
    this_.Parent 
HAVING 
    count(this_.Parent) >= /* names.Length */; 

私は有望な結果を返されたテストアプリケーションを作成しました。

子をページングまたはフェッチするなど、親と一緒にもっと多くのことを行う必要がある場合は、この問題をサブクエリに分割できます(.Fetch(x=>x.Children).Eager行は必須ではありません。クエリ):Fetchなし

var parentSubQuery = 
    QueryOver.Of<Child>() 
    .WhereRestrictionOn(x => x.Name).IsIn(names) 
    .Select(Projections.Group<Child>(x => x.Parent)) 
    .Where(Restrictions.Ge(Projections.Count<Child>(x => x.Parent), names.Length)); 

var parents = session.QueryOver<Parent>() 
    .Fetch(x=>x.Children).Eager // not necessary, just an example 
    .WithSubquery.WhereProperty(x => x.Id).In(parentSubQuery) 
    .List(); 

SQL():

SELECT 
    this_.Id as Id1_0_ 
FROM 
    Parent this_ 
WHERE 
    this_.Id in (
     SELECT 
      this_0_.Parent as y0_ 
     FROM 
      Child this_0_ 
     WHERE 
      this_0_.Name in (
       /* names */ 
      ) 
     GROUP BY 
      this_0_.Parent 
     HAVING 
      count(this_0_.Parent) >= /* names.length */ 
    ); 

更新:

場合は、親< - >子供は、物事は少しトリッキー取得する多対多さ:

 Parent parent = null; 
     var parentSubQuery = QueryOver.Of<Child>() 
     .WhereRestrictionOn(x => x.Name).IsIn(names) 
     .JoinQueryOver(x => x.Parents,() => parent) 
     .Where(Restrictions.Ge(Projections.Count(() => parent.Id), names.Length)) 
     .Select(Projections.Group(() => parent.Id)); 

     var parents = session.QueryOver<Parent>() 
     .WithSubquery.WhereProperty(x => x.Id).In(parentSubQuery) 
     .List(); 

主な違いは、代わりに私が最初の両親コレクションに参加するために必要なChildの直接Parentプロパティによってグループ化することです。そこに各親を参照するために別名parentを紹介します。

生成されたSQLは、独創的なアプローチにかなり近いです:私のテストシナリオでは

SELECT 
    this_.Id as Id2_0_ 
FROM 
    Parent this_ 
WHERE 
    this_.Id in (
     SELECT 
      parent1_.Id as y0_ 
     FROM 
      Child this_0_ 
     inner join 
      ChildToParent parents3_ 
       on this_0_.Id=parents3_.ChildId 
     inner join 
      Parent parent1_ 
       on parents3_.ParentId=parent1_.Id 
     WHERE 
      this_0_.Name in (
       /* names */ 
      ) 
     GROUP BY 
      parent1_.Id 
     HAVING 
      count(parent1_.Id) >= /* names.Length */ 
    ); 

それが動作するので、うまくいけば、それはあなたのためになります、あまりにも。

+0

aw man、それはすばらしいことですが、クエリに少し影響を及ぼすのは、1つのChildが単一のChildだけでなく多くの親を持つことができることです。だから '.Select(Projections.Group (x => x.Parent.Id))'はコンパイルされませんでしたか?ありがとう! – shenku

+0

申し訳ありませんが、私はすでに寝ました。親<->子どもが多対多であるため、NHで行うのがずっと難しくなります。私は少しテストする必要があります。お待ちください:-) –

+0

多対多を扱うために私の答えを更新しました。 –

関連する問題