我收到了以下内容(这个问题已经简化了):
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表没有所有学生的记录。难民价值适当地返回价值或者" IT WAS NULL"当Student_Program_Participation_Values中缺少记录时。但是,难民专栏会返回" NOT NULL!"或者"首先返回NULL!"。
我的问题是,为什么"首先返回NULL!"因为在我使用Linq的经验中,在一个空集上调用First()应该抛出一个异常,但是在这个查询中它似乎做了一些完全不同的事情。请注意,refg.Value在数据库中永远不会为空(它是有效值,或者没有记录)。
另请注意,这是Linq to SQL,我们在Linqpad中运行此查询。
澄清一下,这里有一些示例输出:
StudentId Refugees Refugee 22122 True NOT NULL! 2332 IT WAS NULL First Returned NULL!
在上述情况下,当难民返回" IT是否为空时" Student_Program_Participation_Values表中没有记录,所以我希望First()抛出异常,但是它是null,因此难民显示"首先返回NULL!"。
有什么想法吗?
更新:Enigmativity推动我朝着正确的方向前进,指出我是第一个()时遇到了First()调用,而First()根本不是一个函数调用,而只是简单地翻译成& #34; 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),因为整个事情都是基于外部联接,整个查询只是简单地合并为“第一次返回NULL!”#。
因此,在我看来,Linq To SQL(以及LINQ to Entities)与在列表等上调用相同命名的方法非常不同,这本身就是一种认知错误。
我希望我的错误对其他人有用。
答案 0 :(得分:0)
如果没有您的数据库,我无法测试此代码,但无论如何都要尝试,看看它是否有效。
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有时可能会略微偏离,因此您无法获得预期的结果。这就像将英语翻译成法语一样 - 您可能无法获得正确的翻译。