Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Entity framework EF中的过滤器包括_Entity Framework_Linq - Fatal编程技术网

Entity framework EF中的过滤器包括

Entity framework EF中的过滤器包括,entity-framework,linq,Entity Framework,Linq,我有一个LINQ查询,它在Include中给出了一个过滤器错误。 在搜索我的朋友Google时,我发现无法在包含中进行过滤。我已经找到了一些方法来做这件事,但我不能让它在我的具体情况下工作 return context.Timesheets.Where(t => t.UserId == userId && t.SubjectDate == date && t.WorkingDaySchedules.Count() > 0) .Include(t

我有一个LINQ查询,它在Include中给出了一个过滤器错误。 在搜索我的朋友Google时,我发现无法在包含中进行过滤。我已经找到了一些方法来做这件事,但我不能让它在我的具体情况下工作

return context.Timesheets.Where(t => t.UserId == userId && t.SubjectDate == date && t.WorkingDaySchedules.Count() > 0)
    .Include(t => t.Project)
    .Select(t => t.Project)
        .Include(p => p.Account)
        .Include(pc => pc.ProjectConsultants.Where(c => c.UserId == userId));
这是最后一个让我头疼的内容:)
有人知道怎么做吗?

我认为有几点需要改进


包含不用于过滤。 这根本不是这样做的正确地点

Include
用于自动检索所有链接实体。因为您不需要所有的实体(您只需要一个子集),所以不应该使用
包含

或者,您仍然可以使用
Include
,只要您愿意删除内存中的不需要的条目(即在加载之后)。但我想你不会想要的

相反,您可以使用显式的
Select
语句。举个简单的例子:

context.Projects
             .Where(p => p.Id == projectId)
             .Select(p => new ConsultantSearchResult() {
                   Project = p,
                   ConsultantsNamedBob = p.Consultants.Where(c => c.FirstName == "Bob")
              }).ToList();
注意没有包含
。如前所述,
Include
用于自动(隐式)加载相关数据。但是,由于您在
选择中明确说明了所需的数据,因此不再需要隐式包含。EF会给你你想要的


您的
选择不直观
我想你期待的和你得到的不一样。看看代码:

return context.Timesheets    //1
    .Where(...)              //2
    .Select(t => t.Project)  //3
看看发生了什么:

  • 您可以选择所有时间表
  • 您过滤了时间表,并留下了时间表的子集
  • 您将获得每个时间表的项目列表
  • 如果筛选(步骤2)给您留下了来自同一项目的多个时间表,那么
    。选择(t=>t.project)
    将为您提供同一项目的多个实例。这可不好

    这里有两个例外:

    • 知道你总共会找到一张时间表。但是您应该先使用
      First
      Single
      FirstOrDefault
      SingleOrDefault
      。只有在可能得到多个结果的情况下,才应使用
      Where
    • 您希望有多个时间表,但您知道在同一个项目中永远找不到两个时间表(因此在调用
      选择
      时永远不会创建重复的时间表)。我会假设(通过阅读实体名称),一个特定的顾问可能会为同一个项目提供多个时间表,但可能不是这样。
      
      • 如果我的推断是正确的,那么在执行
        选择后,您将遇到重复项目的问题
      • 如果我的推断不正确,那么我希望时间表和顾问之间的关系会更密切,因为每个项目顾问都有一个(或没有)时间表,而不超过一个。但您当前的数据结构在时间表和顾问之间缺乏任何真正的关系
    一个快速的解决方案是使用
    Distinct

    return context.Timesheets    
        .Where(...)              
        .Select(t => t.Project)  
        .Distinct()
    
    但我个人认为,一个更好的解决方案是反转查找:从项目开始,过滤其时间表上的项目(而不是过滤时间表):

    这就排除了重复项目的问题。请注意,这还不能解决“过滤包含”问题


    同一上下文中的独立查询 评论中也提到了这一点。这是一个可行的选择,但我发现这是一个肮脏的方法,它将创建不直观的代码

    :

    然后你就能得到你想要的。您不再需要进行两次单独的
    userId
    检查,也不再需要“手动同步”假关系,查找过程更加简化,可读性更强


    次要评论 也许有些事你还不知道。你可以重写

    t.WorkingDaySchedules.Count() > 0
    
    作为

    此外,如果需要,您还可以添加过滤器:

    t.WorkingDaySchedules.Any(wds => wds.IsActive)  //is there at least one item in the collection that meets the condition?
    

    有两种方法可以过滤包含实体

    • 使用投影(参见@Flater答案)
    • 使用第三方库
    免责声明:我是项目的所有者

    EF+查询IncludeFilter允许轻松筛选包含的实体

    return context.Timesheets.Where(t => t.UserId == userId && t.SubjectDate == date && t.WorkingDaySchedules.Count() > 0)
        .Include(t => t.Project)
        .Select(t => t.Project)
            .IncludeFilter(p => p.Account)
            .IncludeFilter(pc => pc.ProjectConsultants.Where(c => c.UserId == userId));
    
    在引擎盖下,库正好做了一个投影

    一个限制是all
    Include
    ,但现在可以使用
    IncludeFilter
    调用,即使没有指定诸如帐户之类的筛选器


    Wiki:

    您可以在单独的查询中加载数据,上下文将连接数据。另外,我不认为包含项目比选择包含项目更重要。这是一个更常见的问题。
    t.WorkingDaySchedules.Count() > 0
    
    t.WorkingDaySchedules.Any() //is there at least one item in the collection?
    
    t.WorkingDaySchedules.Any(wds => wds.IsActive)  //is there at least one item in the collection that meets the condition?
    
    return context.Timesheets.Where(t => t.UserId == userId && t.SubjectDate == date && t.WorkingDaySchedules.Count() > 0)
        .Include(t => t.Project)
        .Select(t => t.Project)
            .IncludeFilter(p => p.Account)
            .IncludeFilter(pc => pc.ProjectConsultants.Where(c => c.UserId == userId));