Linq 查询,其中 First() 在找不到结果时似乎返回 null



我得到了以下内容(这个问题已经简化了(:

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 有时可能会有点偏差,因此您无法获得预期的结果。这就像将英语翻译成法语 - 您可能无法获得正确的翻译。

相关内容

  • 没有找到相关文章

最新更新