检查列表是否包含EntityFramework中其他列表中的项目

Ken*_*eth 29 c# linq database entity-framework

我有一个实体Person,它有一个与之关联的位置列表.我需要查询人员表并从位置列表(标准)中获取至少有一个位置的所有人员.以下工作但效率很低:

var searchIds = new List<int>{1,2,3,4,5};
var result = persons.Where(p => p.Locations.Any(l => searchIds.Any(id => l.Id == id)));
Run Code Online (Sandbox Code Playgroud)

这适用于小型列表(例如5-10个searchIds和5-10个位置的人.问题是有些人可能有100个位置,搜索也可以同时用于100个位置.当我尝试执行上述操作时EF实际上产生了一个2000+以上的SQL语句并因为嵌套太深而失败.虽然嵌套本身已经是一个问题,即使它可以工作,我仍然不会发生2000+ SQL语句.

注意:真正的代码还包括多个级别和父子关系,但我确实设法只使用id而不是完整对象将其归结为这个相当扁平的结构

在EF中实现这一目标的最佳方法是什么?

Ivo*_*Ivo 59

我建议:

var searchIds = new List<int>{1,2,3,4,5};
var result = persons.Where(p => p.Locations.Any(l => searchIds.Contains(l.Id)));
Run Code Online (Sandbox Code Playgroud)

Contains将被翻译成IN声明.

请记住,id列表会进入sql语句.如果你的id列表很大,那么你最终会得到一个巨大的查询.

  • 对于我的搜索列表中有 2000 多个 ID 的情况,没有解决方案吗?例如,在 SQL 中,我可以创建一个临时表,将 id 存储在其中,然后在 JOIN 子句中使用它。 (4认同)

Tim*_*out 6

尝试切换到联接而不是执行大量数据包括:

var searchIds = new List<int>{1,2,3,4,5};
var results = (from p in persons
               join l in Location on p.PersonId equals l.PersonId
               where searchIds.Contains(l.Id)
               select p).Distinct().ToList();
Run Code Online (Sandbox Code Playgroud)

显然,修复此行以匹配您的类和/或连接属性.

join l in Location on p.PersonId equals l.PersonId
Run Code Online (Sandbox Code Playgroud)

我希望能够产生更友好的执行计划.

  • 我和你一起讨论 ORM,所以这将是一个快速的讨论 :-) 不幸的是我不能使用连接,因为我没有设置位置(使用通用存储库)。我确实发现做`searchIds.Contains(l.Id)`比`searchIds.Any(id =&gt; l.Id == id)`好很多。减少到大约 70 行 SQL,不是超级但比 2000+ 更好 (2认同)