我正在尝试获取一个父实体,其中子集合中的所有实体都在另一个列表中。
例如:
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 :(得分: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>();
这个想法如下:找到Name
个names
条目之一的所有孩子。按照Parent
对这些孩子进行分组。您的Child
将需要一个映射到相应父级的Parent
属性,但无论如何这都是个好主意。对于大小等于(或大于,但不应该发生,因此您可以将Ge
替换为Eq
)names.Length
的所有群组,请返回其父级;因为如果组的大小等于names.Length
,则找到所有名称假设没有父母的两个孩子具有相同的名称。
生成的查询:
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
行不是必需的,这只是一个示例,您可以进一步处理查询):
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(没有Fetch
):
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&lt; - &gt; Child是多对多的,那么事情会变得有点棘手:
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();
主要区别在于,我首先需要加入父母集合,而不是按Parent
的直接Child
属性进行分组。为了引用每个父母,我引入了一个别名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 */
);
对于我的测试场景,它有效,所以希望它也适合你。