通过GroupBy查找最大值时抛出了“Sequence contains no elements”异常

3

我有以下语句,使用 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个回答

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?>

谢谢你的回答,但 a? 给我的是 ...可能不包含空传播运算符 - renakre
这是一个空值检查。如果你在表达式中工作,例如使用 a.Any() ? a : 0 - kara
给我报错了。你可以在 OP 中检查更新。但是,以某种方式使用 s.LearningActions.SelectMany(la => la.ProgressUpdates) .GroupBy(d => d.LearningActionId) .Select(a => a.Max(d => d.Progress)).Any() 就可以工作了。我不明白为什么 a.Any() 不像你建议的那样工作... - renakre
我不明白为什么a.Any()没有像你建议的那样工作。 问题不在于Average中使用的任何对象都不包含任何元素。问题出现在更高一级。Select没有返回任何元素来执行Average - Mihaeru
1
DefaultIfEmpty() 帮助解决了错误。感谢您的努力!!! - renakre

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

谢谢您的回答!您能举个例子来说明“您是否可以创建一个合理的默认对象”吗?仅使用DefaultIfEmpty()就可行吗? - renakre

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接