LINQ 中子项的子项的总和

本文关键字:LINQ | 更新日期: 2023-09-27 18:36:31

我需要 EF6 中 LINQ 查询的帮助。

主表称为 EXAM 。它的子表是 ExamResult 。每个ExamResult都有一个Question和选定的Answer。每个Answer都有power(如果错误,则为 0,如果正确,则为 1)。如果我想知道正确答案的总数,我只需运行以下命令:

var examTotal = db.Exams.FirstOrDefault(ex => ex.ExamID == examId).ExamResults.Sum(er => er.Answer.Power);

我的问题是当一些问题没有得到回答时,我得到了NullReferenceException.

LINQ 中子项的子项的总和

你的"命令"有几个问题。

首先,至少有两个查询:

(1) var exam = db.Exams.FirstOrDefault(ex => ex.ExamID == examId);

(2) var examTotal = exam.ExamResults.Sum(er => er.Answer.Power);

请注意,第二个实际上是在 LINQ to Objects 上下文中执行的(最终包括由于延迟加载而隐藏的一些数据库调用)。在这种情况下,有两个可能的地方可以提高 NRE

(A) exam.ExamResults如果exam为空
(B) er.Answer.Power如果er.Answer为空

您可以通过包含其他答案中建议的空检查来修复它们。

但更好的方法是让您的命令在 LINQ to 实体上下文中执行单个查询,其中导航属性具有不同的含义:

var examTotal = db.Exams.Where(ex => ex.ExamID == examId)
    .SelectMany(ex => ex.ExamResults)
    .Sum(er => (int?)er.Answer.Power) ?? 0;

唯一需要的技巧是将要求和的字段投影为可为空的类型(我使用过int?假设Power字段是int类型,如果不同,请将其更改为您的类型)。这允许 EF 始终返回Sum,无论er.Answer为 null 还是ex.ExamResults为空。

一些一般的空检查应该可以解决问题

var exam = db.Exams.FirstOrDefault(ex => ex.ExamID == examId);
var examTotal = exam.ExamResults.Sum(er => er.Answer?.Power ?? 0);

。以防万一你没有使用 C# 6,下面是它的另一个版本:

var exam = db.Exams.FirstOrDefault(ex => ex.ExamID == examId);
var examTotal = exam.ExamResults.Sum(er => er.Answer != null ? er.Answer.Power : 0);

试试这个:

var examTotal = db.Exams.FirstOrDefault(ex => ex.ExamID == examId).ExamResults.Where(er => er.Answer != null).Sum(er => er.Answer.Power);

这应该有效:

var examTotal = db.Exams.FirstOrDefault(ex => ex.ExamID == examId).ExamResults.Count(er => er.Answer.Power == 1);

这将不使用该值,而是查看它是否等于 1,因此不会生成任何NullReferenceException