I have the following statement, where I use GroupBy
to calculate the maximum value, and I check if there are any records beforehand using Any()
but this query still returns Sequence contains no elements exception
error. Any ideas?
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());
Just in case it is needed here is the baseQuery
IQueryable<Submission> baseQuery = _context.Submissions
.Where(s => s.ReviewRoundId == reviewRoundId);
I also tried the following as an alternative:
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());
But it throws:
Query source (from LearningActionProgress d in [a]) has already been associated with an expression.
UPDATE
The following code worked:
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
I had to put this check s.LearningActions.SelectMany(la => la.ProgressUpdates).GroupBy(d => d.LearningActionId).Select(a => a.Max(d => d.Progress)).Any()
But, I see this a bit redundant, how can I include this check
in a better way?
Your problem is the .Average(a => a.Max)
. a can be null or empty. You have to check it:
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));
If you want to use this code you could shorten it a little bit. You don't need the anonymous class:
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?>
Can you create a reasonable default object for using 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());
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.