通过GroupBy引发序列查找最大值不包含任何元素异常

时间:2019-11-22 07:02:01

标签: c# entity-framework linq

我有以下语句,其中使用GroupBy计算最大值,并且使用Any()事先检查是否有任何记录,但是此查询仍然返回Sequence contains no elements exception错误。有什么想法吗?

baseQuery = baseQuery.Where(s => s.LearningActions.SelectMany(la => la.ProgressUpdates)
                     .GroupBy(d => d.LearningActionId)
                     .Select(a => a.Any() ? new { Max = a.Max(d => d.Progress) } : new { Max = 0})
                     .Average(d => d.Max) < averageProgress.GetValueOrDefault());

仅在需要的情况下是baseQuery

 IQueryable<Submission> baseQuery = _context.Submissions                 
             .Where(s => s.ReviewRoundId == reviewRoundId);

我还尝试了以下方法:

baseQuery = baseQuery.Where(s => s.LearningActions.SelectMany(la => la.ProgressUpdates)
                      .GroupBy(d => d.LearningActionId)
                      .Select(a => new { Max = (int?) a.Max(d => d.Progress) })
                      .Average(a => a.Max.GetValueOrDefault()) < averageProgress.GetValueOrDefault());

但是它抛出:

  

查询源(来自[a]中的LearningActionProgress d)已与表达式关联。

更新

以下代码有效:

 baseQuery = baseQuery.Where(s => s.LearningActions.SelectMany(la => la.ProgressUpdates)
                                                      .GroupBy(d => d.LearningActionId)
                                                      .Select(a => a.Max(d => d.Progress)).Any() ?
                                                      s.LearningActions.SelectMany(la => la.ProgressUpdates)
                                                      .GroupBy(d => d.LearningActionId)
                                                      .Select(a => a.Max(d => d.Progress)).Average() > averageProgress.GetValueOrDefault() : false); // Here a can be null or empty

我不得不把这张支票s.LearningActions.SelectMany(la => la.ProgressUpdates).GroupBy(d => d.LearningActionId).Select(a => a.Max(d => d.Progress)).Any()

但是,我认为这有点多余,如何更好地包含此check

2 个答案:

答案 0 :(得分:1)

您的问题是.Average(a => a.Max)。 a可以为null或为空。您必须检查它:

IEnumerable<Submission> baseQuery = new List<Submission>()
    {
        new Submission()
            {
                LearningActions = new List<LearningAction>()
                    {
                        //new LearningAction() { ProgressUpdates = null }, // will throw nullRef
                        new LearningAction() { ProgressUpdates = new List<ProgressUpdate>() }, // this is your problem
                    },
            }
    };

int? averageProgress = 100;

baseQuery = baseQuery.Where(
    s => s.LearningActions.SelectMany(la => la.ProgressUpdates)
         .GroupBy(d => d.LearningActionId)
         .Select(a => a.Any() ? new { Max = a.Max(d => d.Progress) } : new { Max = 0 })
         .Average(a => a?.Max) < averageProgress.GetValueOrDefault()); // Here a can be null or empty
         // For Expressions use Any again:
         // .Average(a => a.Any() ? a : 0) < averageProgress.GetValueOrDefault());

Console.WriteLine(string.Join("\n\n", baseQuery));

如果要使用此代码,可以将其缩短一点。您不需要匿名类:

baseQuery = baseQuery.Where(
    s => s.LearningActions.SelectMany(la => la.ProgressUpdates)
         .GroupBy(d => d.LearningActionId)
         .Select(a => a?.Max(d => d.Progress)) // select the "int?"
         .Average() < averageProgress.GetValueOrDefault()); // Average can be performed on the resulting IEnumerable<int?>

答案 1 :(得分:1)

您可以使用DefaultIfEmpty创建一个合理的默认对象吗?

MSDN: DefaultIfEmpty

baseQuery = baseQuery.Where(s => s.LearningActions.SelectMany(la => la.ProgressUpdates)
                     .GroupBy(d => d.LearningActionId)
                     .Select(a => a.Any() ? new { Max = a.Max(d => d.Progress) } : new { Max = 0})
                     .DefaultIfEmpty(defaultItem)
                     .Average(d => d.Max) < averageProgress.GetValueOrDefault());