Страницы

Поиск по вопросам

воскресенье, 15 декабря 2019 г.

There is already an open DataReader associated with this Connection which must be closed first

#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. Кстати, я не утверждаю, что это хорошие варианты в данном случае. Однако они тоже помогут решить проблему и могут быть полезны в некоторых других ситуациях.

Комментариев нет:

Отправить комментарий