#c_sharp #mysql #entity_framework
Есть следующий метод: public static bool IfStudentHasProblems(CollegeContext db, Student student, ControlPoint cp) { foreach (var mark in db.Marks.Where(m => m.Student.StudentId == student.StudentId)) { if (mark.ControlPoint == cp && mark.Value < 4) return true; } return false; } При обращении к db.Marks выбрасывает исключкение выше. Код вызывающий метод: private void groupComboBox_SelectedIndexChanged(object sender, EventArgs e) { if (groupComboBox.SelectedIndex != 0) { int num = Convert.ToInt32(groupComboBox.SelectedItem); selectedGroup = db.Groups.FirstOrDefault(g => g.Number == num); studentListView.Items.Clear(); foreach (var student in db.Students.Where(s => s.Group.Number == selectedGroup.Number).OrderBy(s => s.LastName).ThenBy(s => s.FirstName)) if (CalculationUtils.IfStudentHasProblems(db, student, selectedCP)) studentListView.Items.Add(student.LastName + " " + student.FirstName).BackColor = Color.Goldenrod; else studentListView.Items.Add(student.LastName + " " + student.FirstName); if (selectedCP != null) WriteStatistics(); } else { selectedGroup = null; studentListView.Items.Clear(); } } Так же есть похожий метод, который выполняется без ошибок: public static int CountStudentsWithBadMarks(CollegeContext db, Group group, ControlPoint cp) { int c = 0; foreach (var m in db.Marks.Where(m => m.Student.Group.Number == group.Number)) if (m.ControlPoint.Date == cp.Date) if (m.Value < 4) c++; return c; } Помогите пожалуйста разобраться, где ошибка и как исправить.
Ответы
Ответ 1
Такое происходит потому что вы пытаетесь делать один запрос к БД в то время пока идет перебор результатов другого запроса к БД. Если посмотреть какие запросы к БД вы делаете, то получится как-то вот так: foreach (var student in db.Students.Where(...)) { foreach (var mark in db.Marks.Where(m => m.Student.StudentId == student.StudentId)) { // ... } } Исправить проблему можно несколькими способами: (не работает для MySQL) разрешить соединению иметь несколько открытых дата ридеров - добавить MultipleActiveResultSets=true в строку подключения к БД; материализовать внешний запрос foreach (var student in db.Students.Where(...).ToList()) { foreach (var mark in db.Marks.Where(m => m.Student.StudentId == student.StudentId)) { // ... } } использовать навигационные свойства вместо дополнительных запросов совместно с eager loading: foreach (var student in db.Students.Where(...).Include(s => s.Marks)) { foreach (var mark in student.Marks) { // ... } }Ответ 2
Также для решения данной проблемы, можно использовать разные объекты контекста базы данных. В вашем случае, наверно, как-то так public static bool IfStudentHasProblems(Student student, ControlPoint cp) { using (var db = new CollegeContext()) { foreach (var mark in db.Marks.Where(m => m.Student.StudentId == student.StudentId)) { if (mark.ControlPoint == cp && mark.Value < 4) return true; } return false; } Но в комментариях подсказывают, что контекст нежелательно создавать в цикле из-за возможного снижения производительности. Ну значит можно вынести создание контекста за цикл. using (var db2 = new CollegeContext()) { foreach (var student in db.Students .Where(s => s.Group.Number == selectedGroup.Number) .OrderBy(s => s.LastName) .ThenBy(s => s.FirstName)) { if (CalculationUtils.IfStudentHasProblems(db2, student, selectedCP)) { studentListView.Items.Add(student.LastName + " " + student.FirstName) .BackColor = Color.Goldenrod; } else { studentListView.Items.Add(student.LastName + " " + student.FirstName); } } } P.S. Кстати, я не утверждаю, что это хорошие варианты в данном случае. Однако они тоже помогут решить проблему и могут быть полезны в некоторых других ситуациях.
Комментариев нет:
Отправить комментарий