【问题标题】:Linq query where First() appears to return null when results are not found当未找到结果时,其中 First() 似乎返回 null 的 Linq 查询
【发布时间】: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


    【解决方案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() 调用上卡住的感知问题。谢谢,我会用我发现的内容更新我的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-30
    • 2018-03-05
    • 2010-09-25
    相关资源
    最近更新 更多