Страницы

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

понедельник, 9 декабря 2019 г.

Помогите разобраться в ошибке: Существует назначенный этой команде Command открытый DataReader, который требуется предварительно закрыть

#c_sharp #entity_framework #linq



  Сведения об исключении: System.InvalidOperationException: Существует 
  назначенный этой команде Command открытый DataReader, который
  требуется  предварительно закрыть.


Ошибка источника: 

namespace Library.Controls
{
    public partial class CategoryList : System.Web.UI.UserControl
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }

        protected IEnumerable GetCategories()
        {


            return new Repository().namebook
                .Select(p => p.genre_book.NAME_GENRE)
                .Distinct()
                .OrderBy(x => x);
        }

        protected string CreateHomeLinkHtml()
        {
            string path = RouteTable.Routes.GetVirtualPath(null, null).VirtualPath;
            return string.Format("Главная", path);
        }

        protected string CreateLinkHtml(string category)
        {
            string selectedCategory = (string)Page.RouteData.Values["category"]
              ?? Request.QueryString["category"];

            string path = RouteTable.Routes.GetVirtualPath(null, null,
                new RouteValueDictionary() { { "category", category },
                    {"page", "1"} }).VirtualPath;

            return string.Format("{1}",
                path, category);
        }
    }
}


а вот так выглядит repository 

public class Repository
{
    private EFDbContext context = new EFDbContext();

    public IEnumerable namebook
    {
        get { return context.namebook; }
    }


code-behind формы где я пытаюсь фильтровать книги 

public IEnumerable Getbook()
{
    return repository.namebook
        .OrderBy(b => b.ID_BOOK)
        .Skip((CurrentPage - 1) * pageSize)
        .Take(pageSize);
}


private IEnumerable FilterBook()
{
    IEnumerable namebook = repository.namebook;
    string currentCategory = (string)RouteData.Values["category"] ??
        Request.QueryString["category"];
    return currentCategory == null ? namebook:
        namebook.Where(p => p.genre_book.NAME_GENRE == currentCategory);
}

    


Ответы

Ответ 1



Когда вы перебираете элементы в последовательности без предварительной материализации (.ToList()) - то все это время висит открытый DataReader с результатами запроса к БД. В тот момент, когда EF пытается сделать ленивую загрузку - делается еще один запрос к БД. Тут-то и срабатывает ограничение - в каждом соединении с БД может быть только один активный запрос. Если вы используете MS SQL Server, то можно дописать к строке подключения параметр MultipleActiveResultSets=True - это снимет ограничение. Для других СУБД такой ситуации нужно избегать. Например, через предварительную материализацию запросов (т.е. расстановку этих .ToList()).

Ответ 2



Необходимо материализовать ваш запрос в любую коллекцию return new Repository().namebook // для Distinct придется реализовать IEquatable .Distinct() .OrderBy(p => p.genre_book.NAME_GENRE) .Select(p => p.genre_book.NAME_GENRE) .ToArray(); Пока вы не материализовали коллекцию, ваш запрос не выполнен и соответственно ридер не закрыт

Ответ 3



На мой взгляд, проблема в том, что Вы пытаетесь быстро выполнить один и тот же запрос дважды (предыдущий еще не успел отработать). Обычно данная проблема появляется с весьма тяжелыми запросами. Чтобы включить данную возможность надо подправить ConnectionString - добавьте "MultipleActiveResultSets=True". Подробнее здесь и здесь. P.S. Ранняя материализации - это не всегда хорошо.

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

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