我正在过滤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.
谢谢!
答案 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
端正确配置tblType
和tblType
之间的关系,并且在使用.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语句。