当未找到结果时,其中 First() 似乎返回 null 的 Linq 查询
Posted
技术标签:
【中文标题】当未找到结果时,其中 First() 似乎返回 null 的 Linq 查询【英文标题】:Linq query where First() appears to return null when results are not found 【发布时间】:2015-02-10 07:49:07 【问题描述】:我收到了以下信息(已针对问题进行了简化):
int programId = 3;
int refugeeId = 5;
var q = ( from st in Students
join cr in Class_Rosters on st.StudentId equals cr.StudentId
join pp in Student_Program_Part on cr.StudentId equals pp.StudentId
from refg in (Student_Program_Participation_Values
.Where(rudf => rudf.ProgramParticipationId == pp.ProgramParticipationId
&& rudf.UDFId == refugeeId)).DefaultIfEmpty()
where cr.ClassId == 22898
&& pp.ProgramId == programId
select new
StudentId = st.StudentId,
Refugees = refg.Value ?? "IT WAS NULL",
Refugee = Student_Program_Participation_Values
.Where(rudf => rudf.ProgramParticipationId == pp.ProgramParticipationId
&& rudf.RefugeeId == refugeeId)
.Select(rudf => (rudf.Value == null ? "IT WAS NULL" : "NOT NULL!"))
.First() ?? "First Returned NULL!",
);
q.Dump();
在上述查询中,Student_Program_Participation_Values 表没有所有学生的记录。当 Student_Program_Participation_Values 中缺少记录时,难民值会正确返回值或“IT WAS NULL”。但是,难民列返回“NOT NULL!”或“第一次返回 NULL!”。
我的问题是,为什么“First Returned NULL!”此后,根据我对 Linq 的经验,在空集上调用 First() 应该会引发异常,但在此查询中,它似乎在做一些完全不同的事情。请注意,数据库中的 refg.Value 永远不会为空(它要么是有效值,要么没有记录)。
另请注意,这是 Linq to SQL,我们正在 Linqpad 中运行此查询。
为了澄清,这里是一些示例输出:
StudentId 难民 难民 22122 真不为空! 2332 它是 NULL 首先返回 NULL!在上面,当 Refugees 返回“IT WAS NULL”时,Student_Program_Participation_Values 表中没有记录,所以我希望 First() 抛出异常,但它是 null,所以 Refugee 显示“First Returned NULL!”。
有什么想法吗?
更新:神秘性将我推向正确的方向,指出当我是 IQueryable 时,我被困在 First() 调用上,First() 根本不是函数调用,而是简单地翻译成“TOP 1” “在查询中。当我查看 LINQPad 中生成的 SQL 时,这一点很明显。下面是生成的 SQL 的重要部分,它清楚地说明了正在发生的事情和原因。我不会粘贴整个内容,因为它非常庞大且与讨论无关。
...
COALESCE((
SELECT TOP (1) [t12].[value]
FROM (
SELECT
(CASE
WHEN 0 = 1 THEN 'IT WAS NULL'
ELSE CONVERT(NVarChar(11), 'NOT NULL!')
END) AS [value], [t11].[ProgramParticipationId], [t11].[UDFId]
FROM [p_Student_Program_Participation_UDF_Values] AS [t11]
) AS [t12]
WHERE ([t12].[ProgramParticipationId] = [t3].[ProgramParticipationId]) AND ([t12].[UDFId] = @p8)
), 'First Returned NULL!') AS [value3]
...
所以,在这里您可以清楚地看到 Linq 将 First() 转换为 TOP (1) 并且还确定“IT WAS NULL”永远不会发生(因此 0 = 1),因为整个事情都是基于外部join 并且整个查询简单地合并为“First Returned NULL!”。
因此,我认为 Linq To SQL(以及就此而言的 LINQ to Entities)与在列表等上调用同名方法非常不同,这完全是我的一个认知错误。
我希望我的错误对其他人有用。
【问题讨论】:
【参考方案1】:如果没有您的数据库,我无法测试此代码,但还是尝试一下,看看它是否有效。
var q =
(
from st in Students
join cr in Class_Rosters on st.StudentId equals cr.StudentId
where cr.ClassId == 22898
join pp in Student_Program_Part on cr.StudentId equals pp.StudentId
where pp.ProgramId == programId
select new
StudentId = st.StudentId,
refg =
Student_Program_Participation_Values
.Where(rudf =>
rudf.ProgramParticipationId == pp.ProgramParticipationId
&& rudf.UDFId == refugeeId)
.ToArray()
).ToArray();
var q2 =
from x in q
from refg in x.refg.DefaultIfEmpty()
select new
StudentId = x.StudentId,
Refugees = refg.Value ?? "IT WAS NULL",
Refugee = refg
.Select(rudf => (rudf.Value == null ? "IT WAS NULL" : "NOT NULL!"))
.First() ?? "First Returned NULL!",
;
q2.Dump();
基本上,这个想法是从数据库中干净地捕获记录,将它们放入内存,然后执行所有null
的工作。如果这可行,那是因为未能将 LINQ 转换为相同的 SQL。翻译后的 SQL 有时会有些偏差,因此您无法获得预期的结果。这就像将英语翻译成法语 - 您可能无法得到正确的翻译。
【讨论】:
Enigmativity,感谢您的回复,但我并不是真的在寻找替代解决方案。在我原来的解决方案中,暴露为“难民”的外部连接工作正常。如果不清楚,我很抱歉,但我想了解的问题是:在我的示例中,为什么 First() 调用没有引发异常,即使显然 Select 必须不返回任何结果。 @ScottGartner - 我认为您需要了解代码正在被转换为 SQL,并且没有实际调用.First()
。因此,为什么没有例外。
我不敢相信在提出答案之前我没有查看 SQL。当然,你是对的,这是我在 First() 调用上卡住的感知问题。谢谢,我会用我发现的内容更新我的答案。以上是关于当未找到结果时,其中 First() 似乎返回 null 的 Linq 查询的主要内容,如果未能解决你的问题,请参考以下文章
JavaScript对象函数和`this`,当未绑定并在表达式/括号中返回时