如何在 C# 中的 Sum() 方法中获取 TimeSpan 属性的总数?

how to get total of TimeSpan properties inside a Sum() methode in c#?

我现在正在做一个 Asp.Net 核心项目。我有一个名为 Course 的实体和一个名为 Episode 的实体。它们具有一对多关系,因此每个 Course 内部都有许多 Episods

这是我的 Episode.cs:

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
  }

我的问题是关于这部分的:public TimeSpan? EpisodeTimeLength { get; set; }

我想使用方法 OrderBy() 对我的课程进行排序,以便哪个课程的总 EpisodeTimeLength 排在第一位。

比如我第一个Course的总EpisodeTimeLength是12h,第二个是15h,那么会先考虑第二个。

我尝试了以下方法:

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));

但是其中 none 起作用了,我得到了错误:无法将类型 'System.TimeSpan' 隐式转换为 'long'!

所以谁能告诉我我该如何处理?

您的 TimeSpan 变量可以为空,因此您需要在表达式中使用 Value 并且不需要在 LINQ 方法中创建 TimeSpan 对象。此代码应该有效:

dbContext.Courses.OrderBy( c => c.Episodes.Sum(e=> e.EpisodeTimeLength.Value.Ticks));

因为TimeSpan已经定义了一个operator +,你可以使用它。试试这个:

.OrderBy(c => c.Episodes.Select(e => e.EpisodeTimeLength.Value)
  .Aggregate(TimeSpan.Zero, (x, y) => x + y))

这首先将所有剧集投影到其长度的 Value 上(假设如果剧集长度没有值,您想要一个错误的例外),然后使用内置的 + 运算符进行聚合。

如果您不希望出现异常,但希望在长度未知时使用零长度,那么:

.OrderBy(c => c.Episodes.Select(e => e.EpisodeTimeLength ?? TimeSpan.Zero)
  .Aggregate(TimeSpan.Zero, (x, y) => x + y))

如果您完全确定每门课程总是至少有一集 c,那么您可以省略 Aggregate 调用(第二行)中的 TimeSpan.Zero .那就是

.OrderBy(c => c.Episodes.Select(e => e.EpisodeTimeLength.Value)
  .Aggregate((x, y) => x + y))

分别

.OrderBy(c => c.Episodes.Select(e => e.EpisodeTimeLength ?? TimeSpan.Zero)
  .Aggregate((x, y) => x + y))

最后,您可能需要这样的逻辑:如果至少有一集缺少长度,那么总数应该是未定义的 (null)。在那种情况下,使用 Nullable<> 上自动存在的提升 +。那将是:

.OrderBy(c => c.Episodes.Select(e => e.EpisodeTimeLength)
  .Aggregate((TimeSpan?)TimeSpan.Zero, (x, y) => x + y))

或:

.OrderBy(c => c.Episodes.Select(e => e.EpisodeTimeLength)
  .Aggregate((x, y) => x + y))

如果您知道 .Episodes 不为空,在这些情况下,您将在最短课程之前自行排序所有总长度为“未定义”的课程。


当然,.Select 并不是严格需要的,因为它们可以内置到 .Aggregate 使用的 lambda 中,例如:

.OrderBy(c => c.Episodes
  .Aggregate((TimeSpan?)TimeSpan.Zero, (x, y) => x.EpisodeTimeLength + y.EpisodeTimeLength))

好吧,既然 .OrderBy 就是您所要求的,您不妨按照 fatherOfWine 的小小回答所建议的那样使用 .Ticks。但是,我在您对他的回答的评论中看到您可能希望保留总课程长度。在这种情况下,您可以只说 .Select 而不是 .OrderBy,例如:

var allCourseLengths = dbContext.Courses
  .Select(c => c.Episodes.Select(e => e.EpisodeTimeLength.Value)
  .Aggregate(TimeSpan.Zero, (x, y) => x + y));

等等。