我最近更新了 EF Core 6 到 7,现在一个查询变得比以前慢了很多,没有任何变化。看起来 EF Core 将 LINQ 查询转换为不同的 SQL 查询。
版本:
这是 LINQ 查询:
int userId = 3;
List<string> labels = new () { "one", "two", "three" };
List<RecordEntity> alreadySyncedEvents = await _dbContext.RecordEntities
.IgnoreQueryFilters()
.Where(x => x.UserId == userId)
.Where(x => labels.Contains(x.Label))
.Include(x => x.ExtraData)
.ToListAsync();
这是生成的SQL:
SELECT [a].[Id], [a].[Label], [a0].[Id], [a0].[ExtraData]
FROM [RecordEntities] AS [a]
LEFT JOIN [ExtraDataEntities] AS [a0] ON [a].[Id] = [a0].[RecordId]
WHERE ([a].[UserId] = 3) AND ([a].[Label] IN (N'one', N'two', N'three') OR ([a].[Label] IS NULL))
ORDER BY [a].[Id]
问题是
OR ([a].[Label] IS NULL)
导致此查询返回超过 13k 条记录,而在切换到 EF Core 7 之前它返回 1。它唯一添加的是额外的 OR
条件。
这是因为我不使用可为空的引用类型并且该字符串默认情况下可为空吗? 可空引用类型在此项目中被完全禁用。
由于他们在 EF Core 7 中更改了
OR
运算符的行为,因此您需要显式检查空值。
使用
||
运算符将以下检查添加到您的第二个 Where()
中,例如:
.Where(x => labels.Contains(x.Label) || x.Label == null)
它应该像旧的 EF 那样工作。
你可以添加一个额外的条件
.Where(x => labels != null && labels.Contains(x.Label))
这似乎是一个错误,尽管您可能想检查
UseRelationalNulls(true)
的配置,另请参阅https://learn.microsoft.com/en-us/ef/core/querying/null-comparisons#using -关系空语义