EF 中的过滤器包含[重复]

2024-04-21

我有这个 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是为了自动检索所有链接的实体。既然你不想all的实体(您只想要一个子集),您不应该使用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。正如我之前所说,Include是用来自动地(并且隐式地)加载相关数据。但因为你明确地中注明您想要的数据Select,不再需要隐式包含。 EF 将会满足您的需求。


Your Select不直观

我认为你所期待的东西与你得到的东西不同。看代码:

return context.Timesheets    //1
    .Where(...)              //2
    .Select(t => t.Project)  //3

看看会发生什么:

  1. 您选择所有时间表。
  2. 您过滤时间表并留下时间表的子集
  3. 您将获得项目列表每个时间表的.

如果您的过滤(第 2 步)留给您multiple来自同一项目的时间表,然后.Select(t => t.Project)会给你multiple同一项目的实例。那不好。

这里有两个例外:

  • You know您将总共找到一张时间表。但那么你应该使用First, Single, FirstOrDefault or SingleOrDefault。你应该只使用Where如果您有可能获得多个结果。
  • You expect more than one timesheet, but you know that you'll never find two timesheets from the same project (thus never creating duplicates when you call the Select). I would assume (by reading the entity names) that it's possible for a specific consultant to have multiple timesheets for the same project, but maybe that's not true.
    • 如果我的推断是正确的,那么在执行以下操作后,您将遇到重复项目的问题Select.
    • 如果我的推论不正确,那么我预计时间表和顾问之间的关系会更牢固,因为每个项目顾问都会有 1 个(或没有)时间表,永远不会超过 1 个。但是您当前的数据结构缺乏时间表之间的任何真正关系和顾问。

一个快速的解决方案是使用Distinct:

return context.Timesheets    
    .Where(...)              
    .Select(t => t.Project)  
    .Distinct()

但我个人认为更好的解决方案是反向查找:从项目开始,过滤项目在他们的时间表上(而不是过滤时间表):

return context.Projects    
    .Include(p => p.Timesheets)  
    .Where(p => p.Timesheets.Any(t => t.UserId == userId && ...))              
    .ToList();  

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


同一上下文中的单独查询

评论中也提到了这一点。这是一个可行的选择,但我发现这是一种肮脏的方法,会创建不直观的代码。

一个简单的例子 https://stackoverflow.com/questions/11917926/loading-related-entities-in-separate-queries-and-sorting-of-children-collection:

context.Configuration.LazyLoadingEnabled = false;
var parent = context.Set<Entity>().First(e => e.Name = "ABC");
// Load relations in separate query
context.Set<Child>()
       .Where(c => c.Parent.Name == "ABC")
       .OrderBy(c => c.Name) // You can at least try it but as mentioned above it may not work in all scenarios
       .Load();
// Now parent.Children collection should be filled 

该示例使用OrderBy代替Where,但两者的工作方式相同。

即使您分别查询子级和父级,它们的导航属性也会不断更新,因为您在同一上下文中运行查询。

这对你来说是一个可行的选择,但我对这段代码有点担心,因为它绝不是readable第二个查询会改变第一个查询的结果。
对我来说,这感觉同样肮脏。具有业务逻辑get or set的财产。它可以工作,但会导致意外的行为,并使调试变得非常困难。

请注意,可能会很清楚to you幕后发生了什么,但不同的开发人员在查看代码时很容易掩盖它。

我个人不喜欢这样,但你的意见可能会有所不同。


您不完整的数据结构使其变得复杂。

查看您的代码示例,我认为您的数据一致性存在一些问题。您正在使用userId在两个地方进行过滤:

  • 时间表:t => t.UserId == userId
  • 顾问:c => c.UserId == userId

如果时间表与顾问相关,那么这两个实体之间应该存在关系。目前,您的项目有一个时间表列表和一个顾问列表,但时间表和顾问之间没有明显的关系。
这就是为什么你的查找很复杂。你试图嘲笑一种不存在的关系。

如果这种关系确实存在,那么查找所有内容就会容易得多:

return context.Timesheets
                   .Include(t => t.Project)
                   .Include(t => t.Project.Account)
                   .Include(t => t.Consultant)
                   .Where(t => t.Consultant.UserId == userId && t.SubjectDate == date && t.WorkingDaySchedules.Count() > 0)
                   .ToList()

然后你就得到了你正在寻找的东西。您不再需要单独执行两个操作userId检查后,您不再需要“手动同步”假关系,查找过程更加简化和可读。


小评论

也许有些你还不知道的事情。你可以重写

t.WorkingDaySchedules.Count() > 0

as

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?
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

EF 中的过滤器包含[重复] 的相关文章

  • 如何在 MVC5 中创建两种类型的用户?

    我正在创建 MVC5 应用程序 并且已经在使用 ASP NET Identity 来创建用户 因此 我已经有了 AspNetUsers 表 每当用户注册时 我都会在那里获得一个条目 我还有一个管理员角色 我可以手动指定哪个注册用户是管理员
  • 在运行时更改实体框架数据库架构

    在大多数 ASP NET 应用程序中 您可以通过在运行时修改连接字符串来更改数据库存储 即 我可以通过简单地更改连接字符串中 数据库 字段的值来从使用测试数据库更改为生产数据库 我正在尝试使用实体框架更改架构 但不一定是数据库本身 但没有成
  • Linq-to-Entity Join 与 GroupJoin

    有人可以解释一下什么是GroupJoin is 和普通的有什么不同Join 常用吗 它仅适用于方法语法吗 查询语法怎么样 如果有 C 代码示例就更好了 行为 假设您有两个列表 Id Value 1 A 2 B 3 C Id ChildVal
  • SQL 选择与带有通配符的 URL 匹配的行

    我在数据库中有一个表 其中一列包含一个 URL 例如http example com users http example com users 轮廓 我得到了一个 URL 例如http example com users 234 profi
  • 大表的最佳主键格式

    我正在开发一个 ASP NET 应用程序 它有一些可能很大的数据表 我想知道定义主键的最佳方法是什么 我知道以前已经有人问过这个问题 但由于这是针对特定情况的 所以我认为这个问题是有效的 我在 SQL Server 2008 数据库上使用实
  • 在一个数据库请求中连接 IQueryable 集合

    我使用实体框架 我需要连接两个集合 例如 IQueryable
  • 默认情况下 dbo 架构中的 EF 6 Code First __MigrationHistory

    我是代码优先实体框架的新手 第一次运行我的应用程序后登录数据库时 当我看到 MigrationHistory 表时 我有点困惑 我现在了解对此表的需求 但不喜欢它位于用户表内的标准 dbo 模式中 我认为它很唐突且有风险 我的第一个想法是将
  • EF Core - 可能会导致循环或多个级联路径

    我已经设置了一个我认为非常简单的数据库 但是我收到以下错误 在表 User 上引入 FOREIGN KEY 约束 FK User Suburb SuburbId 可能会导致循环或多个级联路径 指定 ON DELETE NO ACTION 或
  • 识别关系并插入子实体会导致“无法在表中插入标识列的显式值”

    我正在尝试在实体框架中获取可识别的关系 以便我可以使用 删除 从其集合中删除项目 我创建了一个测试 例如 public class OrderLine Key Column Order 0 public int OrderLineId ge
  • 不同提供商的相同 EDMX 文件

    我正在开发一个项目 其中有一个本地数据库 SQL CE 在不存在与服务器的连接的情况下用作缓冲区 在服务器上我想使用相同的数据库布局 当然 我想使用服务器和客户端上可用的 Common dll 中的相同 EDMX 文件 在客户端中 我有一个
  • 尚未为此带有 SQL Server 的 DbContext .NET Core 配置数据库提供程序

    我一直用这个把头撞在墙上 并且一直在谷歌上搜索无济于事 我刚刚开始一个新的 ASP NET Core MVC 项目 我已将这两个包安装 更新为 2 2 0 Microsoft EntityFrameworkCore SqlServer Mi
  • 将 Lambda 表达式树与 IEnumerable 结合使用

    我一直在尝试了解有关使用 Lamba 表达式树的更多信息 因此我创建了一个简单的示例 这是代码 如果作为 C 程序粘贴到 LINQPad 中 它可以工作 void Main IEnumerable
  • EntityFramework 6.0.0.0 读取数据,但不插入

    我创建了一个基于服务的数据库 folderName gt Add New Item gt Data gt Service based Database文件到 WPF 应用程序中 然后我用过Database First方法并创建了Person
  • 按字母顺序对列表进行排序

    我有以下课程 class Detail public Detail details new List
  • 如何使用 EF Code First 解释枚举类型

    这是一个模型 Public class Person Key Public int PersonId get set Public int Age get set Public ColorEnum FavoriteColor get set
  • 二维数组的列求和

    我有一个IEnumerable
  • 数据库优先方法和修改数据库模式

    我正在使用数据库优先方法使用实体框架 DbContext 构建 ASP NET MVC Web 应用程序 如果在某些情况下我需要修改数据库 例如添加新表或修改现有表 添加列或更改列数据类型 我应该 删除现有实体 edmx 和 tt 文件夹并
  • 更改实体的可访问性

    我想建立一个内部实体 我已将实体 其标量属性和导航属性更改为内部 当我尝试构建它时出现此错误 错误 6036 EntityType 文件 具有 内部 可访问性 EntitySet 文件 具有具有 公共 可访问性的 get 属性 Entity
  • 使用左连接获得不适当的输出

    我正在尝试获取变体列表 并且对于每个变体都获取所有subvariants list无论子变体属于何处 特别的Test say 100 这是示例数据 Id TestId SourceSubVariantId TargetSubVariantI
  • 使用 LINQ 获取两个数组中不同和共同的项目

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 help reopen questions 例如 我有

随机推荐