【问题标题】:LINQ Query - how sort and filter on eager fetchLINQ Query - 如何对 Eager fetch 进行排序和过滤
【发布时间】:2011-07-16 13:05:56
【问题描述】:

如何对父子关系进行急切查询:

  1. 过滤子字段
  2. 按父子排序
  3. 返回一个列表或父母预先填充了孩子

如果我尝试

from p in _context.Parents.Include("children")
join c in _context.childrenon p.Id equals c.ParentId 
where d.DeletedDate == null
orderby p.Name ascending, c.Name 
select p

然后我取回 Parent 对象,但每个 Parent 的孩子都为 NULL

如果我尝试

from p in _context.Parents.Include("children")
orderby p.Name ascending
select p

查询返回所有父母和孩子,但他们没有被过滤或排序。

我想要返回的结果是IEnumerable<Parent>

Parent[0].name = "foo"
Parent[0].children = IEnumerable<Child>
Parent[1].name = "bar"
Parent[1].children = IEnumerable<Child>

【问题讨论】:

  • 我假设每个父母可能有零个或多个孩子。当父母有多个孩子时,预期的输出是什么?
  • @tvanfosson 我已经用这个信息更新了我的问题

标签: linq entity-framework-4 linq-to-entities


【解决方案1】:

没有直接的方法可以做到这一点,但您可以使用某种解决方法 - 将父级和子级投影到一个匿名对象上,然后从该对象中选择并返回父级。

查看类似问题:Linq To Entities - how to filter on child entities

在您的情况下,您将拥有以下内容:

var resultObjectList = _context.
                       Parents.
                       Where(p => p.DeletedDate == null).
                       OrderBy(p => p.Name).
                       Select(p => new
                                 {
                                     ParentItem = p,
                                     ChildItems = p.Children.OrderBy(c => c.Name)
                                 }).ToList();

List<Parent> resultingCollection = resultObjectList.Select(o => o.ParentItem).ToList();

【讨论】:

  • 我现在正在尝试这种方式,当它生成正确的 SQL 但结果Collection 没有填充子项时。无论如何要从匿名类型转换回带有子列表的父对象?或者我应该只是制作一个与匿名类型匹配的新视图模型(我正在使用 mvc .net)
【解决方案2】:

解决方案取决于您到底想做什么。

第一个查询给人的印象是你想“扁平化”对象中的结果,就像这样(伪代码,我希望我的意思很清楚):

{ Parent1, Child1 }
{ Parent1, Child2 }
{ Parent1, Child3 }
{ Parent2, Child1 }

在这种情况下,每个结果“行”将是一个具有 ParentChild 属性的对象,您可以先按父名称排序,然后再按子名称排序。

第二个查询只返回Parent 对象并且(您没有显示它,但我假设EF 已被指示这样做)每个都有一个Children 集合。在这种情况下,您只能按父名称排序;如果您想对每个Parent 的子项进行排序,请自行对该对象上的Children 集合进行排序。

这两个你想做哪一个?

更新

好的,看来您想要第二个。我不相信它可以直接完成。您可以在枚举结果时执行此操作 - 因为 Parents 已经排序,只需对每个孩子的孩子进行排序:

var sortedChildren = parent.Children.OrderBy(c => c.Name);

【讨论】:

  • 我更喜欢第二个选项。我的最终目标是使用 optGroup 标签分组的选择框
  • 如果我错了,请纠正我,但是您是否建议从数据库中获取父母,然后在内存中进行排序?
  • 我让它使用 Selecting ALL data 然后在内存中排序。是的,这可能不是最有效的,但我的数据集很小,很容易编写 p.Chilren.Where(x => x.DeletedDate == null).OrderBy(x => x.Name);在每个父母的循环中
  • @Daveo - 是的,如果您没有大量数据,这可能并不重要,但如果您想在数据库级别订购,请随时在我的回答中使用解决方法.
  • @Yakimych:投影到匿名类型并在查询中排序是否会使 EF 以某种方式将其转换为 SQL?如果是这样,那么我会非常有兴趣学习它。如果没有,那么无论如何都会在内存中进行排序。
【解决方案3】:

预取子字段:

using (BlogDataContext context = new BlogDataContext())
{
    DataLoadOptions options = new DataLoadOptions();
    options.LoadWith<Blog>(c => c.Categories);
    options.LoadWith<Blog>(c => c.Title);
    context.LoadOptions = options;
    Blog blog = context.Blogs.Single<Blog>(c => c.BlogId == 1);
}

【讨论】:

  • 我认为 LoadOptions 仅适用于 DataContext,不适用于 Entity.DbContext
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-04
  • 2012-04-01
  • 1970-01-01
相关资源
最近更新 更多