У меня сложный запрос LINQ, который я изо всех сил пытаюсь понять. У меня есть такая модель домена:
ReviewCategory > has ReviewQuestions > has ReviewAnswers
То, что я пытаюсь сделать, - вычислить количество ответов на определенное значение для всех вопросов в категории. Я строю из очень старой классической системы asp, которая использует несколько хранимых процедур базы данных, чтобы это сделать, но я думаю, что это можно управлять с помощью LINQ to EF.
У меня есть ViewModel, что я устанавливаю имя категории, порядок и счетчик для каждого значения ответа, поэтому модель представления будет содержать список категорий и расчеты количества ответов.
Вот код, на который я застрял:
pcvm.Categories = from x in _repository.GetAll<ReviewCategory>()
where x.include == true &&
((x.AuditQuestionGroupId != null ? x.AuditQuestionGroupId : 0) == this.LoggedInEntity.AuditQuestionGroupId)
from y in x.Questions
where y.include == true
from z in y.Answers
where z.entityId == this.LoggedInEntity.EntityId
orderby x.order != null ? 999 : x.order, x.name
group x by new { x.id, x.name, x.order, z.yourEvaluation, z.yourResponse } into newGroup
select new PracticeConductCategoriesViewModel
{
Id = newGroup.Key.id, // The categoryId
Name = newGroup.Key.name, // The category name
Order = newGroup.Key.order, // The category order
EvaluationNR = newGroup.Key.yourEvaluation, // The number of answers where yourEvaluation = 0
Evaluation1 = newGroup.Key.yourEvaluation, // The number of answers where yourEvaluation = 1 etc etc.
Evaluation2 = newGroup.Key.yourEvaluation,
Evaluation3 = newGroup.Key.yourEvaluation,
Evaluation4 = newGroup.Key.yourEvaluation,
Percentage = newGroup.Key.yourEvaluation // Percentage of yourEvaluations answered for each category
};
Поэтому, по сути, я пытаюсь группировать суммы по значениям внуков. Я добавил в комментарии значения, которые я пытаюсь вернуть в ViewModel, но я не могу понять, как сделать подсчет ответов. Должны ли ответы быть в группе или они должны быть в другом запросе после этой группировки? Если да, то как мне использовать переменную z после группы.
Я получаю неправильный список категорий, поскольку я получаю только категории, на которые есть ответы. Но я знаю, что могу использовать из/в /isdefault, поэтому, пожалуйста, не беспокойтесь об этом.
Это оптимизированная версия вышеуказанного ответа.
var categories = (from x in _repository.GetAll<ReviewCategory>()
from y in x.Questions
where y.include == true && x.include == true &&
((x.AuditQuestionGroupId != null ? x.AuditQuestionGroupId : 0) == this.LoggedInEntity.AuditQuestionGroupId)
group x by new { category = x } into newGroup
select new ConductCategoriesViewModel
{
Id = newGroup.Key.category.id,
name = newGroup.Key.category.name,
order = newGroup.Key.category.order != null ? newGroup.Key.category.order : 999,
Evaluation1 = newGroup.Key.category.Questions.SelectMany(a => a.Answers)
.Count(b => b.Question.radioDisplay == true && b.Question.include == true && b.yourEvaluation == 1 && b.entityId == this.LoggedInEntity.EntityId && b.entityLevelAudit == true),
Evaluation2 = newGroup.Key.category.Questions.SelectMany(a => a.Answers)
.Count(b => b.Question.radioDisplay == true && b.Question.include == true && b.yourEvaluation == 2 && b.entityId == this.LoggedInEntity.EntityId && b.entityLevelAudit == true),
Evaluation3 = newGroup.Key.category.Questions.SelectMany(a => a.Answers)
.Count(b => b.Question.radioDisplay == true && b.Question.include == true && b.yourEvaluation == 3 && b.entityId == this.LoggedInEntity.EntityId && b.entityLevelAudit == true),
Evaluation4 = newGroup.Key.category.Questions.SelectMany(a => a.Answers)
.Count(b => b.Question.radioDisplay == true && b.Question.include == true && b.yourEvaluation == 4 && b.entityId == this.LoggedInEntity.EntityId && b.entityLevelAudit == true),
EvaluationNR = newGroup.Key.category.Questions.SelectMany(a => a.Answers)
.Count(b => b.Question.radioDisplay == true && b.Question.include == true && b.yourEvaluation == 0 && b.entityId == this.LoggedInEntity.EntityId && b.entityLevelAudit == true),
Response1 = newGroup.Key.category.Questions.SelectMany(a => a.Answers)
.Count(b => b.Question.radioDisplay == true && b.Question.include == true && b.yourResponse == 1 && b.entityId == this.LoggedInEntity.EntityId && b.entityLevelAudit == true),
Response2 = newGroup.Key.category.Questions.SelectMany(a => a.Answers)
.Count(b => b.Question.radioDisplay == true && b.Question.include == true && b.yourResponse == 2 && b.entityId == this.LoggedInEntity.EntityId && b.entityLevelAudit == true),
Response3 = newGroup.Key.category.Questions.SelectMany(a => a.Answers)
.Count(b => b.Question.radioDisplay == true && b.Question.include == true && b.yourResponse == 3 && b.entityId == this.LoggedInEntity.EntityId && b.entityLevelAudit == true),
QuestionsAnswered = newGroup.Key.category.Questions.SelectMany(x => x.Answers)
.Count(b => b.yourEvaluation != null && b.entityId == this.LoggedInEntity.EntityId && b.entityLevelAudit == true && b.Question.include == true && b.Question.radioDisplay == true),
TotalQuestions = newGroup.Key.category.Questions.Count(x => x.include == true && x.radioDisplay == true) == 0 ? 0 : newGroup.Key.category.Questions.Count(x => x.include == true && x.radioDisplay == true)
})
.OrderBy(x => x.order != null ? x.order : 999).ThenBy(x => x.name) // It doesn't sort properly if this is in the linq query for some reason.
.ToList();
return categories;
Я понял это (мой мозг почти взорвался, делая это). Мне потребовалось некоторое время, чтобы понять, что, поскольку у меня не было вопросов или ответов в группе (иначе они бы не группировались по категориям), мне пришлось передать весь объект категории в выбранный новый, а затем доступ к внукам (ответы другим подзапросом) таким образом.
Вот рабочий код:
PracticeConductViewModel pcvm = new PracticeConductViewModel();
pcvm.Categories = (from x in _repository.GetAll<ReviewCategory>()
where x.include == true &&
((x.AuditQuestionGroupId != null ? x.AuditQuestionGroupId : 0) == this.LoggedInEntity.AuditQuestionGroupId)
from y in x.Questions
where y.include == true
group x by new { x, x.id, x.name, x.order } into newGroup
orderby newGroup.Key.order != null ? 999 : newGroup.Key.order, newGroup.Key.name
select new PracticeConductCategoriesViewModel
{
Id = newGroup.Key.id, // The categoryId
name = newGroup.Key.name, // The category name
order = newGroup.Key.order, // The order
Evaluation1 = (from a in newGroup.Key.x.Questions
from b in a.Answers
where b.yourEvaluation == 1 && b.entityId == this.LoggedInEntity.EntityId
select a).Count(),
Evaluation2 = (from a in newGroup.Key.x.Questions
from b in a.Answers
where b.yourEvaluation == 2 && b.entityId == this.LoggedInEntity.EntityId
select a).Count(),
Evaluation3 = (from a in newGroup.Key.x.Questions
from b in a.Answers
where b.yourEvaluation == 3 && b.entityId == this.LoggedInEntity.EntityId
select a).Count(),
Evaluation4 = (from a in newGroup.Key.x.Questions
from b in a.Answers
where b.yourEvaluation == 4 && b.entityId == this.LoggedInEntity.EntityId
select a).Count(),
EvaluationNR = (from a in newGroup.Key.x.Questions
from b in a.Answers
where b.yourEvaluation == 0 && b.entityId == this.LoggedInEntity.EntityId
select a).Count(),
Response1 = (from a in newGroup.Key.x.Questions
from b in a.Answers
where b.yourResponse == 1 && b.entityId == this.LoggedInEntity.EntityId
select a).Count(),
Response2 = (from a in newGroup.Key.x.Questions
from b in a.Answers
where b.yourResponse == 2 && b.entityId == this.LoggedInEntity.EntityId
select a).Count(),
Response3 = (from a in newGroup.Key.x.Questions
from b in a.Answers
where b.yourResponse == 3 && b.entityId == this.LoggedInEntity.EntityId
select a).Count(),
//Percentage = newGroup.Key.yourEvaluation // Percentage of yourEvaluations answered for each question
})
.ToList();
return View(pcvm);
Этот ответ работает, но есть ли способ оптимизировать этот код?
.Count(x => bla)
вместо.Where(x => bla).Count()
.