LINQ to Entities生成错误的SQL

时间:2013-09-23 19:55:11

标签: linq entity-framework null

我正在过滤IQueryable以返回将UserId(可空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.

谢谢!

5 个答案:

答案 0 :(得分:34)

这是EF在知道肯定时查询不会返回任何结果时生成的查询类型。这样的查询可以最大限度地减少数据库处理。

EF如何确定?这只能是因为它知道数据库中的UserId不可为空。反过来,这只能在User(POCO类)中根据需要映射Certificate引用时。寻找像

这样的东西
HasRequired(t => t.User).WithMany(t => t.Certificates)

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

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

答案 1 :(得分:2)

也许您可以尝试更明确的选项

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

答案 2 :(得分:0)

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

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

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

当我查看查询时,它正在执行,它与op相同:

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()时定义两个表之间的关系。

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

答案 3 :(得分:0)

就我而言,当EF(v6.4.0)确定结果为空时,此查询也出现在事件探查器中。这只是简单得多的情况:

var productsIds = new List<int>();

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

EF必须检查productsIds是否为空并生成始终从db返回空的查询。 如果您真的想摆脱此类数据库查询,则可以自己进行检查。

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

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

答案 4 :(得分:-1)

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

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

编辑:在那里意外地有错误的if语句。