EFCore 2.2.2对相关子实体进行过滤

时间:2019-03-03 18:18:12

标签: entity-framework entity-framework-core

我有一个类型为Complex的实体对象。

复合体与论坛的比例为1:1,论坛中有很多主题,每个主题都有很多帖子。我正在尝试对帖子进行分页,但收到我不理解的错误。

Message = ThenInclude属性lambda表达式'p => {p.Posts => Skip((__ pageIndex_0-1))=> Take(__ pageSize_1)}'无效。该表达式应表示属性访问:“ t => t.MyProperty”。要定位在派生类型上声明的导航,请指定目标类型的显式键入的lambda参数,例如'((衍生d)=> d.MyProperty'。

这有效..

 public Complex GetComplexWithForumAndPosts(Guid Id, int pageIndex, int pageSize = 10)
    {
        var complex = CoDBContext.Complexes
            .Include(x => x.Forum)
            .ThenInclude(x => x.Topics)
            .ThenInclude(p => p.Posts)
            .Single(x => x.Id == Id); 

        return complex;
    }

但这不是

public Complex GetComplexWithForumAndPosts(Guid Id, int pageIndex, int pageSize = 10)
    {
        var complex = CoDBContext.Complexes
            .Include(x => x.Forum)
            .ThenInclude(x => x.Topics)
            .ThenInclude(p => p.Posts.Skip((pageIndex-1)*pageSize).Take(pageSize))
            .Single(x => x.Id == Id); 

        return complex;
    }

1 个答案:

答案 0 :(得分:2)

某些背景:Include 不包含的内容

Include方法是个bit子。接受表达式参数的最常用重载(如果存在内存,则自Entity Framework 4.1起就存在)看起来令人怀疑,就像那些通用的LINQ方法用我们提供的最疯狂的表达式来处理各种奇妙的事情一样。

实际上,它和ThenInclude-都是不是 LINQ方法。 (Then)Include只是一种坚固的旧方法,拒绝执行其单一任务之外的任何操作:将导航属性名称传递给EF查询引擎,指示其急于加载具有根实体的集合或引用。可以将其视为Include("PropertyName")的强类型版本。它的 only 目的是启用编译类型类型检查。

这意味着:您只能使用表示导航属性名称的表达式:.ThenInclude(p => p.Posts)是可以的。没有添加任何东西。

expression参数使人们期望它做得更多。那么为何不?代码可以编译,为什么不运行?但不是。常见的失望之处是Include无法被过滤或排序。结合IncludeSkip/Take的工作虽然不常见,但同样可以理解。

对于我来说,EF团队不妨考虑完全放弃这种(Then)Include的重载,现在我们有了nameof关键字,它可以做类似的事情并且可以同样地使用。这将消除所有混乱,无休止地涌入Stack Overflow问题,以及迄今为止从未被映射的永无止境的变更请求。 [也可以理解,但这超出了此问题的范围]。

问题

与此同时,您仍然遇到问题。 Skip/Take经常不与Include结合使用的原因是很难想象它应该做什么。只是假设您在其中嵌套了两个IncludesThenInclude(x => x.Topics.Skip().Take().ThenInclude(p => p.Posts))(如果有支持,则应该都是同等合法的){em>两个。实际上,只有在查询的根实体上进行分页才是明确定义的。

因此,您只能通过查询帖子来获取分页的帖子。例如这样的

CoDBContext.Posts
    .Where(p => p.Topic.Forum.ComlexId = Id)
    .Skip((pageIndex-1)*pageSize).Take(pageSize))

这也是比带有Includes的查询更精简的查询。

如果您需要更多上下文信息,例如在Complex上,可以考虑在一次呼叫中查询Complex,将其保留在页面上(如果这是SPA)并查询帖子在随后的ajax调用中。