【问题标题】:How to select values in list that are NOT IN a Table using EF Core?如何使用 EF Core 在列表中选择不在表中的值?
【发布时间】:2019-04-11 05:33:15
【问题描述】:

我有一个相当大的字符串列表 (30k+),我需要使用 Entity Framework Core 检查表中不存在哪些字符串。

类似这样,但没有为每个项目发送检查请求:

var notFoundItems = hugeList.Where(c => !tableToCheck.Any(x => x.Id == c)).ToList();

我找到了答案,但使用的是T-SQL

【问题讨论】:

  • 我不确定,但我认为 LINQ 不会为每个项目生成查询。你检查了吗?
  • 好吧,至少这是我的 EF Core Oracle 驱动程序正在执行的操作
  • 您应该创建一个临时表(或永久表),清空并上传hugeList 并在服务器端进行检查。该 T-SQL 解决方案将具有相同的参数限制问题 - 我知道,您不能在单个查询中传输 30k 的字符串。您可以一次将它们批处理成 2000 个参数,但我认为这足够大,不能这样做。

标签: c# entity-framework linq entity-framework-core ef-core-2.1


【解决方案1】:

T-SQL 可能是一个不错的方法,但在您的情况下,您必须创建一个临时表并进行连接。 30k 并不是太多的记录,所以在应用端比较记录可能会更容易一些。在这种情况下,您可以这样做:

var idList = tableToCheck.Select(x => x.id).ToList();
var notFoundItems = hugeList.Where(item => idList.All(id => id != item));

由于数据库中的字符串是 ID,因此您可以做得更好并使用复杂度为 O(1) 的 HashSet 和 Contains 方法:

var idSet = tableToCheck.Select(x => x.id).ToHashSet();
var notFoundItems = hugeList.Where(item => !idSet.Contains(item));

最终,性能取决于数据库中数据集的大小。如果 DB 表很大并且您必须获取数百万个 ID,那么 T-SQL 方法会更快。

【讨论】:

  • 此方法是否对列表中的最大项目数有任何限制。在之前的回答 cmets 上有关于 2100 的限制的讨论?
  • 否,该示例中的 Contains() 被转换为 SQL 并完全在 DB 端执行(LINQ to SQL)。这个例子只在 DB 端执行第一个选择,然后在应用端过滤元素,因此它没有这个限制。
【解决方案2】:

由于您已经有了 T-SQL 解决方案,因此这是使用 Raw SQL Query 的好案例。肯定会有 SQL 查询无法用 LINQ 表达或 LINQ 语句无法生成优化查询的情况。

【讨论】:

    【解决方案3】:

    您可以选择搜索表中存在的所有字符串并放入列表中。在你检查了哪些字符串不存在之后。

    例子:

    var foundItems = tableToCheck
                    .Where(x => hugeList.Contains(x.id))
                    .Select(x => x.id)
                    .Distinct()
                    .ToList();
    
    var notFoundItems = hugeList.Where(c => !foundItems.Any(x => x == c)).ToList();
    

    这样你只对数据库执行一个请求。

    【讨论】:

    • 这是一个解决方案,但需要再次迭代 hugeList,这不是最优的。
    • 它也不起作用,因为Contains 转换为IN== OR 并且仅限于大约2100 个参数(至少,对于MS SQL Server)。
    • @NetMage 如果 EF 驱动程序足够聪明,它将创建多个 IN 语句来规避此限制,所以这不是问题。
    • @user2457870 你知道吗? MS SQL Server 驱动程序不是。
    • 我没有使用 MS SQL Server,但 Devart for Oracle 可以!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多