为何以下EF Core查询中First()方法未抛出无序列异常?
问题
以下是一段EF Core查询代码:
var aaa = _dbContext.IdentityAppUsers .Where(x => x.Uuid == 'ABC') .SelectMany(l => l.OrganisationOrganisationUsers) .Select(x => x.Organisation!.OrganisationStandards .Select(od => od.Uuid).First());
当OrganisationStandards为空集合时,我原本预期这段查询里的First()方法会抛出序列为空的异常,但实际并没有抛出。生成的SQL如下:
SELECT ( SELECT o1.uuid FROM query.organisation_standard AS o1 WHERE o0.id = o1.organisation_id LIMIT 1) FROM query.identity_app_user AS i INNER JOIN query.organisation_organisation_user AS o ON i.id = o.user_id INNER JOIN query.organisation_organisation AS o0 ON o.organisation_id = o0.id WHERE i.uuid = 'ABC'
原因分析
这是因为EF Core把LINQ中的First()方法翻译成了SQL里的LIMIT 1(不同数据库可能是TOP 1这类等价语法),而SQL的子查询如果没有匹配结果,只会返回NULL,不会抛出任何异常。
你预期的“序列为空异常”是内存中LINQ操作的行为——只有在内存集合上调用First()且集合为空时,才会抛出InvalidOperationException。但这里EF Core把整个查询下推到数据库执行,所有逻辑都在数据库层面完成,返回的是SQL执行的结果(空的子查询返回NULL),不会触发内存中LINQ的异常逻辑。
如果想要在EF Core中实现“无匹配时抛出异常”的效果,可以先用FirstOrDefault()获取结果,之后在内存中判断是否为NULL再手动抛出;或者根据业务逻辑改用Single()/SingleOrDefault()(注意这两个方法的语义和First()不同)。
内容的提问来源于stack exchange,提问作者ValidfroM
相关产品推荐
相关产品推荐

