29

我正在过滤 IQueryable 以返回所有将字段 UserId(可为 null 的 int)设置为 null 的实体。查询生成不正确的 SQL 因而失败——语句如下——

var filtered = certificates.Where(c => !c.UserId.HasValue).Select(c => c.SubjectName);

生成的 SQL 是——

SELECT 
CAST(NULL AS varchar(1)) AS [C1], 
CAST(NULL AS int) AS [C2], 
CAST(NULL AS datetime2) AS [C3], 
CAST(NULL AS datetime2) AS [C4], 
CAST(NULL AS bit) AS [C5], 
CAST(NULL AS datetime2) AS [C6], 
CAST(NULL AS int) AS [C7]
FROM  ( SELECT 1 AS X ) AS [SingleRowTable1]
WHERE 1 = 0

知道 WTF 正在进行吗?这个想法很简单,我只想返回字段 UserId 为 false 的所有行。UserId 可以为空,并且被查询的表有三行符合所描述的条件,但是 LINQ 查询返回 0。

谢谢!

4

5 回答 5

39

这是 EF 在确定查询不会返回任何结果时生成的那种查询。这样的查询最小化了数据库处理。

EF怎么能这么肯定?这只能是当它知道UserId数据库中的所有内容不可为空时。反过来,这只能是在(POCO 类)中还有一个根据需要映射的User引用时。Certificate寻找类似的东西

HasRequired(t => t.User).WithMany(t => t.Certificates)

在 中EntityTypeConfiguration<Certificate>,或OnModelCreating在您的DbContext. (在代码优先中,可能有一个必需的引用,而随附的原始 Id 属性是可为空的类型。在 edmx 文件中,这不会验证)。

User所以我认为如果在数据库中外键可以为空,你必须映射为可选。

于 2013-09-23T22:36:50.520 回答
2

也许你可以尝试一个更明确的选择

  var filtered = certificates.Where(c => c.UserId == null).Select(c => c.SubjectName);
于 2013-09-23T20:02:32.060 回答
1

我正在添加这个答案,因为我花了很长时间试图诊断这个问题,也许它会对某人有所帮助。

我正在使用 Entity Framework 6.1.3 并注意到当我使用以下查询时,它永远不会返回任何内容,即使数据库中有符合此条件的项目。

dbContext.Items.Where(n => n.TypeID == null)

当我查看它正在执行的查询时,它使用的操作与操作相同:

SELECT 
CAST(NULL AS int) AS [C1], 
CAST(NULL AS int) AS [C2], 
CAST(NULL AS varchar(100)) AS [C3], 
FROM  ( SELECT 1 AS X ) AS [SingleRowTable1]
WHERE 1 = 0

我知道这意味着 EF 认为该字段永远不会为 null 并且返回一个空集,并且当我使用代码优先实体框架设计时,我查看了模型声明tblItems但在这里没有看到任何问题,我什至尝试添加 .属性定义的 Optional() 没有运气。

原来我并没有在侧面正确配置tblItems和之间的关系,而是在定义两个表之间的关系时使用而不是。tblTypetblType.HasRequired().HasOptional()

摘要:如果您看到正在使用此默认查询,并且该表与其他表有关系,请确保在您的模型中正确定义了关系的双方。

于 2019-12-16T17:00:44.587 回答
0

在我的情况下,当 EF(v6.4.0)确定结果为空时,此查询也出现在分析器中。这只是更简单的情况:

var productsIds = new List<int>();

var 结果 = products.Where(p => productsIds.Contains(p.Id)).ToList();

EF 必须检查是否productsIds为空并生成始终从数据库返回空的查询。如果你真的想摆脱这样的数据库查询,你可以自己检查一下。

if (products.Any()) 
{
    var result = products.Where(p => productsIds.Contains(p.Id)).ToList();
}

我希望 EF 可以进一步优化它,并且在这种情况下不做任何数据库查询,但我想最好什么都不做;)

于 2020-06-22T14:16:00.073 回答
-1

我相信它不适合你的原因是 c.UserId 有一个值,它只是空值。您应该将其与 null 进行比较:

var filtered = certificates.Where(c => c.UserId == null).Select(c => c.SubjectName);

编辑:在那里不小心有错误的 if 语句。

于 2013-09-23T20:11:04.067 回答