【发布时间】: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)与在列表等上调用同名方法非常不同,这完全是我的一个认知错误。
我希望我的错误对其他人有用。
【问题讨论】:
标签: sql-server linq linq-to-sql outer-join linqpad