gpt4 book ai didi

c# - 使用 nHibernate 通过子集合限制 QueryOver

转载 作者:行者123 更新时间:2023-11-30 12:14:24 25 4
gpt4 key购买 nike

我正在尝试获取父实体,其中子集合中的所有实体都在另一个列表中。

例如:

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:

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

最佳答案

这是我的建议:

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 进行分组。为此,您的 Child 需要一个映射到相应父级的 Parent 属性,但无论如何这是个好主意。对于大小等于(或大于,但不应发生这种情况,因此您可以将 Ge 替换为 Eq)的所有组 names.Length,返回他们的 parent ;因为如果组的大小等于 names.Length,则所有名称都已找到假设 parent 的两个 child 没有相同的名字

生成的查询:

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

我创建了一个测试应用程序,返回了有希望的结果。

如果你需要对 parent 做更多的事情,比如分页或获取 child ,你可以把这个问题分解成一个子查询(注意 .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<->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();

主要区别在于,我首先需要加入父集合,而不是通过 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 */
);

对于我的测试场景,它有效,所以希望它也适用于您。

关于c# - 使用 nHibernate 通过子集合限制 QueryOver,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9593017/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com