LINQ 中 child 的 child 之和
Sum of child of child in LINQ
我需要有关 EF6 中 LINQ 查询的帮助。
大师table叫EXAM
。它的 child 是 ExamResult
。
每个 ExamResult
都有一个 Question
和选定的 Answer
。
每个 Answer
有 power
(错误为 0,正确为 1)。
如果我想知道正确答案的总数,我只需 运行 命令:
var examTotal = db.Exams.FirstOrDefault(ex => ex.ExamID == examId).ExamResults.Sum(er => er.Answer.Power);
我的问题是有些问题没有得到回答,我得到 NullReferenceException
。
这应该有效:
var examTotal = db.Exams.FirstOrDefault(ex => ex.ExamID == examId).ExamResults.Count(er => er.Answer.Power == 1);
这不会使用该值,而是查看它是否等于 1,因此不会生成任何 NullReferenceException
。
试试这个:
var examTotal = db.Exams.FirstOrDefault(ex => ex.ExamID == examId).ExamResults.Where(er => er.Answer != null).Sum(er => er.Answer.Power);
一些常规的 nullchecks 应该可以解决问题
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);
你的"command"有几个问题。
首先,至少有两个个查询:
(1) var exam = db.Exams.FirstOrDefault(ex => ex.ExamID == examId);
(2) var examTotal = exam.ExamResults.Sum(er => er.Answer.Power);
请注意,第二个实际上在 LINQ to Objects 上下文中执行(由于延迟加载,最终包括一些隐藏的数据库调用)。
在这种情况下,有 2 个可能的地方可以提高 NRE
(A) exam.ExamResults
如果 exam
为空
(B) er.Answer.Power
如果 er.Answer
为空
您可以按照其他答案中的建议通过包括空检查来修复它们。
但更好的方法是让您的命令在 LINQ to Entities 上下文中执行单个查询,其中导航属性具有不同的含义:
var examTotal = db.Exams.Where(ex => ex.ExamID == examId)
.SelectMany(ex => ex.ExamResults)
.Sum(er => (int?)er.Answer.Power) ?? 0;
唯一需要的技巧是将要求和的字段投影为 nullable 类型(我使用 int?
假设 Power
字段是 int
类型,如果不同,请将其更改为您的类型)。这让 EF 始终 return Sum
而不管 er.Answer
是否为空或 ex.ExamResults
是否为空。
我需要有关 EF6 中 LINQ 查询的帮助。
大师table叫EXAM
。它的 child 是 ExamResult
。
每个 ExamResult
都有一个 Question
和选定的 Answer
。
每个 Answer
有 power
(错误为 0,正确为 1)。
如果我想知道正确答案的总数,我只需 运行 命令:
var examTotal = db.Exams.FirstOrDefault(ex => ex.ExamID == examId).ExamResults.Sum(er => er.Answer.Power);
我的问题是有些问题没有得到回答,我得到 NullReferenceException
。
这应该有效:
var examTotal = db.Exams.FirstOrDefault(ex => ex.ExamID == examId).ExamResults.Count(er => er.Answer.Power == 1);
这不会使用该值,而是查看它是否等于 1,因此不会生成任何 NullReferenceException
。
试试这个:
var examTotal = db.Exams.FirstOrDefault(ex => ex.ExamID == examId).ExamResults.Where(er => er.Answer != null).Sum(er => er.Answer.Power);
一些常规的 nullchecks 应该可以解决问题
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);
你的"command"有几个问题。
首先,至少有两个个查询:
(1) var exam = db.Exams.FirstOrDefault(ex => ex.ExamID == examId);
(2) var examTotal = exam.ExamResults.Sum(er => er.Answer.Power);
请注意,第二个实际上在 LINQ to Objects 上下文中执行(由于延迟加载,最终包括一些隐藏的数据库调用)。 在这种情况下,有 2 个可能的地方可以提高 NRE
(A) exam.ExamResults
如果 exam
为空
(B) er.Answer.Power
如果 er.Answer
为空
您可以按照其他答案中的建议通过包括空检查来修复它们。
但更好的方法是让您的命令在 LINQ to Entities 上下文中执行单个查询,其中导航属性具有不同的含义:
var examTotal = db.Exams.Where(ex => ex.ExamID == examId)
.SelectMany(ex => ex.ExamResults)
.Sum(er => (int?)er.Answer.Power) ?? 0;
唯一需要的技巧是将要求和的字段投影为 nullable 类型(我使用 int?
假设 Power
字段是 int
类型,如果不同,请将其更改为您的类型)。这让 EF 始终 return Sum
而不管 er.Answer
是否为空或 ex.ExamResults
是否为空。