我得到了以下内容(这个问题已经简化了(:
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 中缺少记录时,Refugees 值会正确返回值或"It is null"。 但是,难民列返回"NOT NULL!"或"First ReturnNULL!"。
我的问题是,为什么会看到"First Return NULL!",因为根据我对 Linq 的经验,在空集上调用 First(( 应该会引发异常,但在此查询中,它似乎正在做一些完全不同的事情。 请注意,引用。值在数据库中永远不会为 null(它是有效值,或者没有记录(。
另请注意,这是 Linq to SQL,我们在 Linqpad 中运行此查询。
为了澄清,下面是一些示例输出:
学生证难民22122 真不空!2332 为空 首次返回空!
在上面当难民返回"它是空的"中,Student_Program_Participation_Values表中没有记录,所以我预计 First(( 会抛出异常,但它是空的,所以难民显示"第一次返回的 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 is null"永远不会发生(因此 0 = 1(,因为整个事情是基于外部连接的,整个查询只是合并成"First Return NULL!"。
因此,这完全是我的感知错误,没有在我的脑海中分离Linq To SQL(以及LINQ to Entities(与在列表等上调用同名方法非常不同。
我希望我的错误对其他人有用。
没有你的数据库,我无法测试这段代码,但无论如何都要尝试一下,看看它是否有效。
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 有时可能会有点偏差,因此您无法获得预期的结果。这就像将英语翻译成法语 - 您可能无法获得正确的翻译。