C#中如何用Sum方法累加TimeSpan属性实现课程按总时长排序
Asp.Net Core 按课程总时长排序解决方案
问题背景
我正在开发一个Asp.Net Core项目,定义了Course和Episode两个存在一对多关系的实体,每个Course包含多个Episode。
Episode实体代码
public class Episode { [Key] public int EpisodeId { get; set; } [Required] public int CourseId { get; set; } [Display(Name = "عنوان اپیزود")] [Required(ErrorMessage ="لطفا {0} را وارد کنید")] [MaxLength(ErrorMessage ="{0} نمیتواند بیش تر از {1}کاراکتر باشد")] public string EpisodeTitle { get; set; } public string EpisodeFileName { get; set; } [Display(Name = "مدت زمان اپیزود")] [Required(ErrorMessage = "لطفا {0} را وارد کنید")] public TimeSpan? EpisodeTimeLength { get; set; } [Display(Name = "رایگان")] [Required(ErrorMessage = "لطفا {0} را وارد کنید")] public bool IsFree { get; set; } public DateTime CreateDate { get; set; } = DateTime.Now; #region Navigation Properties [ForeignKey("CourseId")] public Course.Courses.Course Course { get; set; } #endregion }
问题描述
我需要使用OrderBy()方法对课程排序,关联Episode的EpisodeTimeLength总时长越长的课程越靠前。比如课程1总时长12小时,课程2总时长15小时,排序后课程2排在首位。
我尝试了以下两种写法:
// 写法1 dbContext.Courses.OrderBy(c => new TimeSpan(c.Episodes.Sum(e=> e.EpisodeTimeLength.Ticks))); // 写法2 dbContext.Courses.OrderBy(c => c.Episodes.Sum(e=> e.EpisodeTimeLength));
均报错:cannot implicity convert type 'System.TimeSpan' to 'long'
解决方案
错误原因
EF Core原生没有支持TimeSpan类型累加的Sum()重载方法,仅支持对long、int等数值类型求和,所以会报类型转换错误。同时你需要时长越长排序越靠前,应该用OrderByDescending(降序)而非OrderBy(升序)。
正确代码
你可以通过对TimeSpan的底层存储单位Ticks求和来实现需求,注意要处理TimeSpan?可空类型的null值:
var sortedCourses = dbContext.Courses // 按总时长降序排列,null的时长按0计算 .OrderByDescending(c => c.Episodes.Sum(e => e.EpisodeTimeLength.HasValue ? e.EpisodeTimeLength.Value.Ticks : 0)) .ToList();
如果你的业务逻辑通过[Required]校验已经保证EpisodeTimeLength不会出现null值,可以简化写法:
var sortedCourses = dbContext.Courses .OrderByDescending(c => c.Episodes.Sum(e => e.EpisodeTimeLength.Value.Ticks)) .ToList();
实现原理
Ticks是TimeSpan的最小时间单位,1秒等于10000000个Ticks,对Ticks求和等价于对时间长度直接求和,EF Core可以正确将该写法翻译为SQL语句执行,不会出现类型转换错误。
内容的提问来源于stack exchange,提问作者Hossein
相关产品推荐
相关产品推荐

