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

195
22 сентября 2017, 17:01

Есть следующий метод:

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;
    }

Помогите пожалуйста разобраться, где ошибка и как исправить.

Answer 1

Такое происходит потому что вы пытаетесь делать один запрос к БД в то время пока идет перебор результатов другого запроса к БД.

Если посмотреть какие запросы к БД вы делаете, то получится как-то вот так:

foreach (var student in db.Students.Where(...))
{
    foreach (var mark in db.Marks.Where(m => m.Student.StudentId == student.StudentId)) 
    {
         // ...
    }
}

Исправить проблему можно несколькими способами:

  1. (не работает для MySQL) разрешить соединению иметь несколько открытых дата ридеров - добавить MultipleActiveResultSets=true в строку подключения к БД;

  2. материализовать внешний запрос

    foreach (var student in db.Students.Where(...).ToList())
    {
        foreach (var mark in db.Marks.Where(m => m.Student.StudentId == student.StudentId)) 
        {
             // ...
        }
    }
  3. использовать навигационные свойства вместо дополнительных запросов совместно с eager loading:

    foreach (var student in db.Students.Where(...).Include(s => s.Marks))
    {
        foreach (var mark in student.Marks) 
        {
             // ...
        }
    }
READ ALSO
MSSQL Server permissions + Entity Framework [Необходимые разрешения]

MSSQL Server permissions + Entity Framework [Необходимые разрешения]

Ранее имел дело с MySQL сервером и понятной установкой разрешений для аккаунтов и объектовСейчас разбираюсь с MSSQL сервером и Entity Framework

161
Захват камеры в Emgu проект на WPF

Захват камеры в Emgu проект на WPF

Пробую EmguА именно захват видео с веб камеры

356
Создание файла c#

Создание файла c#

Есть проблемаСоздаю файл

314
Unity3d - Управление персонажем с помощью touch (C#)

Unity3d - Управление персонажем с помощью touch (C#)

Подскажите пожалуйста каким способом можно сделать управление выбранным персонажем (например кораблем в космосе), через touch (без использования...

271