EF Core中Sum()类型转换异常及无行时返回值疑问
问题描述
现有Answer和Question两个实体类,关联代码如下:
public class Answer { public Guid Id { get; set; } public Guid? QuestionId { get; set; } public virtual Question? Question { get; set; } } public class Question { public Guid Id { get; set; } [MaxLength(1024)] public string Question { get; set; } public int? MaxMarks { get; set; } }
由于仅部分题目需要计分,MaxMarks设为可空类型。执行以下计算总分的代码时抛出异常:
TotalScore = s.Answers .Where(a => a.Question.MaxMarks.HasValue) .Sum(a => a.Question.MaxMarks)
报错信息:
System.InvalidCastException: Unable to cast object of type 'System.Int64' to type 'System.Int32'.
at Microsoft.Data.SqlClient.SqlBuffer.get_Int32()
尝试显式转换为int无效,需明确两个问题:
- 该异常的原因是什么?
- 当
Sum()没有匹配行时,返回值是null还是0?
解答
一、异常原因分析
这是EF(或EF Core)处理可空整数求和时的类型映射冲突:
- SQL Server中,
SUM()函数对int类型字段计算时,默认返回bigint类型(避免累加值超出int的范围限制),但你的实体类中MaxMarks定义为int?。 - EF尝试将SQL返回的
bigint(对应C#的Int64)映射回int?(对应Int32)时,就会触发类型转换异常。 - 你之前的显式转换无效,是因为转换时机错误:如果在LINQ查询中直接转
int,EF会将转换逻辑翻译成SQL,但SQL层面的SUM结果依然是bigint,类型不匹配问题并未解决。
解决方法是先将求和目标转为可空长整型,再按需转换:
// 方式1:转为long?求和后,转成int类型结果 TotalScore = s.Answers .Where(a => a.Question.MaxMarks.HasValue) .Sum(a => (long?)a.Question.MaxMarks) .GetValueOrDefault(); // 方式2:直接用long?接收求和结果 long? TotalScore = s.Answers .Where(a => a.Question.MaxMarks.HasValue) .Sum(a => (long?)a.Question.MaxMarks);
二、Sum()无匹配行时的返回值
分两种情况:
- 若对可空数值类型(如
int?、long?)求和,无匹配行时返回null; - 若对非可空数值类型(如
int、long)求和,无匹配行时返回0。
你的代码是对int?求和,因此无匹配行时会返回null。
内容的提问来源于stack exchange,提问作者AkshatSparrow
相关产品推荐
相关产品推荐

