潜在优化的替代 linq 查询,用于在一组 ID 中查找不存在的记录

Potential Optimised alternative linq query for finding non Existent records within a set of Ids

假设我得到了一组 ID [整数],我想知道其中哪一个不存在于特定 Db table [例如 Table1] 中。目前我使用以下 EF 查询 [我的 EF 版本是 EF6,但我假设在这个特定场景中使用 EF6 或 EF Core 无关紧要]:

// Lets assume record with id = 9999 doesnt exist in the database 
IEnumerable<int> Ids = new [] { 1 ,2 ,3, 4, 9999}

var nonExistentIds = Ids.Except(myDbContext.Table1.Select(x => x.Id)
                                            .Intersect(Ids));

以上示例将 return [9999] 这是给定数组中不存在于数据库中的记录。

是否有潜在的更好的 linq 替代方案[我不是在寻找本机 sql 替代方案] 来发现不存在的记录?

我认为主要的替代方法是使用 .Distinct() 而不是 .Intersect(Ids)。前者会 return 一个更大的数字列表,而后者需要将 ID 列表发送到 SQL 服务器。我不知道什么会更快,它可能最容易测试。

只要Ids比较小,我就用Contains:

var existingIds = myDbContext.Table1.Select(x => x.Id)
                                    .Where(id => Ids.Contains(id))
                                    .ToHashSet();

var nonExistentIds = ids.Where(id => !existingIds.Contains(id));

应该翻译成

SELECT 
    [Extent1].[Id] AS [Id]
    FROM [dbo].[Table1] AS [Extent1]
    WHERE  [Extent1].[Id] IN (1, 2, 3, 4)

然后使用 LINQ to Objects 反转结果。

你也可以用Except反转:

var nonExistentIds = ids.Except(myDbContext.Table1.Select(x => x.Id)
                                                  .Where(id => Ids.Contains(id)));

Contains 相对于 Intersect 的好处是将 ID 列表发送到 SQL 服务器的方式 - Intersect 非常冗长地构造了一个 table , UNION ALL 会更快地溢出 SQL.