Использование GroupBy для вычисления среднего или подсчета на основе целых данных до соответствующей даты - PullRequest
0 голосов
/ 23 октября 2019

У меня есть объект AssessmentItems DB, который содержит элементы о том, какой пользователь оценил (EvaluatorId), какое представление (SubmissionId), на основании какого элемента рубрики (или критериев) (RubricItemId) и когда(DateCreated).

Я группирую по этому объекту по RubricItemId и DateCreated, чтобы вычислить некоторую ежедневную статистику на основе каждого критерия оценки (или элемента рубрики).

НапримерЯ вычисляю AverageScore, который работает нормально и возвращает результат, подобный: RubricItem: 1, Day: 15/01/2019, AverageScore: 3.2.

_context.AssessmentItems
        .Include(ai => ai.RubricItem)
        .Include(ai => ai.Assessment)
        .Where(ai => ai.RubricItem.RubricId == rubricId && ai.Assessment.Submission.ReviewRoundId == reviewRoundId)
        .Select(ai => new
        {
            ai.Id,
            DateCreated = ai.DateCreated.ToShortDateString(),//.ToString(@"yyyy-MM-dd"),
            ai.CurrentScore,
            ai.RubricItemId,
            ai.Assessment.SubmissionId,
            ai.Assessment.EvaluatorId

        })
        .GroupBy(ai => new { ai.RubricItemId, ai.DateCreated })
        .Select(g => new
        {
            g.Key.RubricItemId,
            g.Key.DateCreated,
            AverageScore = g.Average(ai => ai.CurrentScore),
            NumberOfStudentsEvaluating = g.Select(ai => ai.EvaluatorId).Distinct().Count(),

        }).ToList();

Что я хочу сделать, так это вычислить среднее значение до этого дня. Я имею в виду, вместо того, чтобы вычислять среднее значение за день, я хочу получить среднее значение до этого дня (то есть, я хочу учитывать оценки за предыдущие дни). По той же причине, когда я вычисляю NumberOfStudentsEvaluating, я хочу указать общее количество студентов, участвовавших в оценке до этого дня.

Одним из подходов к достижению этой цели может быть итерация объекта result и повторное вычисление этих свойств:

 foreach (var i in result)
 {
     i.AverageScore = result.Where(r => r.DateCreated <= i.DateCreated).Select(r => r.AverageScore).Average(),

 }

Но это довольно дорого. Интересно, можно ли немного подправить код, чтобы добиться этого, или я должен начать с нуля с другим подходом.

1 Ответ

1 голос
/ 23 октября 2019

Если вы разделите запрос на две половины, вы можете вычислить среднее значение по своему усмотрению (я также вычислил NumberOfStudentsEvaluating по тем же критериям), но я не уверен, сможет ли EF / EF Core перевести наSQL:

var base1 = _context.AssessmentItems
    .Include(ai => ai.RubricItem)
    .Include(ai => ai.Assessment)
    .Where(ai => ai.RubricItem.RubricId == rubricId && ai.Assessment.Submission.ReviewRoundId == reviewRoundId)
    .Select(ai => new {
        ai.Id,
        ai.DateCreated,
        ai.CurrentScore,
        ai.RubricItemId,
        ai.Assessment.SubmissionId,
        ai.Assessment.EvaluatorId

    })
    .GroupBy(ai => ai.RubricItemId);

var ans1 = base1
            .SelectMany(rig => rig.Select(ai => ai.DateCreated).Distinct().Select(DateCreated => new { RubricItemId = rig.Key, DateCreated, Items = rig.Where(b => b.DateCreated <= DateCreated) }))
            .Select(g => new {
                g.RubricItemId,
                DateCreated = g.DateCreated.ToShortDateString(), //.ToString(@"yyyy-MM-dd"),
                AverageScore = g.Items.Average(ai => ai.CurrentScore),
                NumberOfStudentsEvaluating = g.Items.Select(ai => ai.EvaluatorId).Distinct().Count(),
            }).ToList();
...