具有字段值的 EF Core 结果存在于数组中

Posted

技术标签:

【中文标题】具有字段值的 EF Core 结果存在于数组中【英文标题】:EF Core results with a field value exists in array 【发布时间】:2021-11-02 09:47:48 【问题描述】:

我想获取用户 StatusId 存在于包含我需要的状态 ID 的数组中的用户数据。

我使用以下代码,但结果是数组中的最后一个值。

int[] statusIds = 1,4,8
IQueryable<User> result = _database.User;

foreach (var item in statusIds)
   
       result = result.Where(x => x.StatusId == item);
   

此代码仅获取 StatusId = 8 的用户。

【问题讨论】:

你试过result.Where(x =&gt; statusIds.contains( x.StatusId)); 【参考方案1】:

在 Where 的结果上连续使用 Where 的问题,就像你在这里做的那样:

foreach (var item in statusIds)

   result = result.Where(x => x.StatusId == item);

当你在前面的 Where 之上复合 Where 时,它​​的作用是 AND,而不是 OR,所以你的查询最终相当于:

_database.User.Where(u => u.StatusId == 1 && u.StatusId == 4 && u.StatusId == 8)

这自然不会产生任何结果,因为没有记录可以同时是所有 3 种状态

旁注:您报告输出只是数组中的最后一个元素,我认为这是与延迟执行和捕获 foreach 循环变量值有关的单独问题(尽管我不相信它会在现代C#)。到执行查询时(循环完成后),循环变量已经使用了 3 次,但查询中使用的值不是变量在每次循环迭代期间的 3 个不同值,而是单个循环的 3 次重复循环结束时它的值。因此,有效地,查询运行是

_database.User.Where(u => u.StatusId == z && u.StatusId == z && u.StatusId == z)

z 的值为 8。从逻辑上讲,这可以工作,因为只测试了一个值。你可以阅读更多关于这个特殊的奇怪之处 here

即使您组合了一个结构来处理“使用变异捕获的循环变量进行延迟执行”问题,您仍然会遇到“statusid = 1 和 4 和 8 肯定是假”的问题,所以您需要另一种方法


类似这样的东西将被映射为x IN (collection):

_database.User.Where(u => statusIds.Contains(u.StatusId))

_database.User.Where(u => statusIds.Any(sid => sid == u.StatusId))

【讨论】:

是的,你是对的,我当时没有任何状态 id 为 8 的记录,所以我认为输出是状态 id 为 8 的记录。【参考方案2】:

问题的解决方案由@Greg 在问题的评论中给出。

我只是想正式布置一下答案。

方法一

int[] statusIds = 1,4,8
IQueryable<User> result = _database.User.Where(x => statusIds.Contains( x.StatusId));

方法2

int[] statusIds = 1,4,8
IQueryable<User> result = _database.User.Where(x => statusIds.Any(n => n == x.StatusId));

这两种方法的区别在于.Contains函数在你需要类似“...WHERE x IN (1,2,3)”结果的SQL查询时使用,这基本上是一个标准的比较情况。

.Any 允许您为多值比较或唯一条件提供自己的谓词。请记住,如果您有大型数据集,谓词将在本地执行,这是一个很大的禁忌。

一般来说,尽量避免.Any。经验法则是将处理卸载到数据库,而不是在本地导入所有记录和过滤。

调试 SQL 查询

要查看 EFCore 生成的实际 SQL 查询(我强烈推荐),请阅读 Christian Findlay 的 blog post。

【讨论】:

以上是关于具有字段值的 EF Core 结果存在于数组中的主要内容,如果未能解决你的问题,请参考以下文章

如何在 MySQL 中选择字段具有最小值的数据?

选择不存在于具有多个字段的同一个表中

EF Core 中DbContext不会跟踪聚合方法和Join方法返回的结果

EF Core 5检查过滤器中的所有ID是不是存在于相关实体中

Oracle 中参数中具有空值的结果

查看单个文档的数组时,mongoose .find() 没有结果