实体框架:查询子实体

ETF*_*fax 45 linq-to-entities entity-framework entity-framework-4.1

我正在学习实体框架,我遇到了问题!

有人可以澄清我是否正确地认为我无法从数据库中获取父母及其子集的子集?

例如...

db.Parents
.Include(p => p.Children)
.Where(p => p.Children.Any(c => c.Age >= 5))
Run Code Online (Sandbox Code Playgroud)

这将返回所有有5岁以上孩子的父母,但如果我遍历Parents.Children集合,所有孩子都将在场(不仅仅是5岁以上的孩子).

现在查询确实对我有意义(我已经要求包含子项,我已经得到了它们!),但可以想象我想在某些场景中将where子句应用于子集合.

问题:

  1. 我说的是对的吗?
  2. 是否有可能从数据库中获取父项和一个子集而无需对数据库进行大量调用?
  3. 我离开了标记吗?(不会是第一次)!!!!

我找到了一些关于这个主题的博客和SO帖子,但没有什么能够解释我的小脑袋.

编辑

读过这个博客(感谢Daz Lewis).......我仍然没有得到它!

在博客中给出的示例中,我可以看到如何针对单个Parent实例实现它,但我正在努力弄清楚如何使用集合来实现它.

我怎么能得到一个IEnumerable,其中每个父母都有一个过滤的儿童集合(年龄> = 5)?

进一步澄清:

在回答DonAndre的评论时,我追问的是a)有5岁以上孩子的父母名单(仅包括那些孩子).

任何帮助,赞赏,

谢谢.

Sla*_*uma 48

在单个数据库往返中获取带有过滤子集合的父集合的唯一方法是使用投影.不能使用eager loading(Include)因为它不支持过滤,所以Include总是加载整个集合.@Daz显示的明显加载方式需要每个父实体一次往返.

例:

var result = db.Parents
    .Select(p => new
    {
        Parent = p,
        Children = p.Children.Where(c => c.Age >= 5)
    })
    .ToList();
Run Code Online (Sandbox Code Playgroud)

您可以直接使用此匿名类型对象集合.(您也可以投射到您自己的命名类型而不是匿名投影(但不会投射到像这样的实体中Parent).)

如果您不禁用更改跟踪(例如,使用),EF的上下文也ChildrenParent自动填充集合AsNoTracking().在这种情况下,您可以将父项目从匿名结果类型中调出(发生在内存中,没有数据库查询):

var parents = result.Select(a => a.Parent).ToList();
Run Code Online (Sandbox Code Playgroud)

parents[i].Children将包含每个过滤后的子项Parent.


编辑到问题的上一个编辑:

我是在a)有一个5岁以上孩子的父母名单(仅包括那些孩子).

上面的代码将返回所有父项,并且仅包括Age> = 5的子项,因此如果只有Age<5的子项,也可能是父项具有空子集合.您可以使用附加Where子句过滤这些子项,以便父项只能获取至少有一个(Any)孩子Age> = 5 的父母:

var result = db.Parents
    .Where(p => p.Children.Any(c => c.Age >= 5))
    .Select(p => new
    {
        Parent = p,
        Children = p.Children.Where(c => c.Age >= 5)
    })
    .ToList();
Run Code Online (Sandbox Code Playgroud)

  • 如果你想在孩子们身上加载虚拟属性怎么办...怎么想? (2认同)

Pri*_*sad 5

在 EF Core 5.0 中,Inclusion 方法现在支持对包含的实体进行筛选。

https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-5.0/whatsnew#filtered-include

var data = db.Parents
    .Include(p => p.Children.Where(c => c.Age >= 5))
    .ToList();
Run Code Online (Sandbox Code Playgroud)