Я использую Entity Framework и иногда получаю эту ошибку.
EntityCommandExecutionException
{"There is already an open DataReader associated with this Command which must be closed first."}
at System.Data.EntityClient.EntityCommandDefinition.ExecuteStoreCommands...
Хотя я не делаю никакого ручного управления соединением.
эта ошибка происходит с перерывами.
код, который вызывает ошибку (сокращен для удобства чтения):
if (critera.FromDate > x) {
t= _tEntitites.T.Where(predicate).ToList();
}
else {
t= new List<T>(_tEntitites.TA.Where(historicPredicate).ToList());
}
используя шаблон Dispose, чтобы каждый раз открывать новое соединение.
using (_tEntitites = new TEntities(GetEntityConnection())) {
if (critera.FromDate > x) {
t= _tEntitites.T.Where(predicate).ToList();
}
else {
t= new List<T>(_tEntitites.TA.Where(historicPredicate).ToList());
}
}
все еще проблематично
почему EF не может повторно использовать соединение, если оно уже открыто.
linq
entity-framework
sql-server-2008
Sonic Soul
источник
источник
predicate
иhistoricPredicate
переменные. Я обнаружил, что если вы перейдетеFunc<T, bool>
кWhere()
нему, он будет компилироваться и иногда работать (потому что он делает «где» в памяти). То , что вы должны делать это проходитExpression<Func<T, bool>>
вWhere()
.Ответы:
Это не о закрытии соединения. EF правильно управляет соединением. Мое понимание этой проблемы состоит в том, что существует несколько команд извлечения данных, выполняемых для одного соединения (или одной команды с множественным выбором), в то время как следующий DataReader выполняется до того, как первая закончит чтение. Единственный способ избежать исключения - разрешить нескольким вложенным DataReaders = включить MultipleActiveResultSets. Другой сценарий, когда это всегда происходит, - это когда вы перебираете результат запроса (IQueryable) и запускаете отложенную загрузку загруженного объекта внутри итерации.
источник
В качестве альтернативы использованию MARS (MultipleActiveResultSets) вы можете написать свой код, чтобы не открывать несколько наборов результатов.
Что вы можете сделать, это извлечь данные в память, таким образом, у вас не будет открытого считывателя. Это часто вызывается повторением набора результатов при попытке открыть другой набор результатов.
Образец кода:
Допустим, вы делаете поиск в вашей базе данных, содержащей эти:
Мы можем сделать простое решение для этого, добавив .ToList () следующим образом:
Это вынуждает объектную структуру загружать список в память, поэтому, когда мы выполняем итерацию, хотя он в цикле foreach, он больше не использует средство чтения данных для открытия списка, а вместо этого находится в памяти.
Я понимаю, что это может быть нежелательно, если вы хотите, например, lazyload некоторых свойств. В основном это пример, который, мы надеемся, объясняет, как / почему вы можете решить эту проблему, чтобы вы могли принимать соответствующие решения
источник
ToList
используете тысячу объектов, это увеличит память на тонну. В этом конкретном примере вам лучше объединить внутренний запрос с первым, чтобы генерировался только один запрос, а не два.Есть еще один способ преодолеть эту проблему. Будет ли это лучше, зависит от вашей ситуации.
Проблема возникает из-за отложенной загрузки, поэтому один из способов избежать ее - не выполнять отложенную загрузку с помощью функции «Включить»
Если вы используете соответствующие
Include
s, вы можете избежать включения MARS. Но если вы пропустите один, вы получите ошибку, так что включение MARS, вероятно, самый простой способ исправить это.источник
.Include
это гораздо лучшее решение, чем включение MARS, и намного проще, чем написание собственного кода SQL-запроса.Вы получаете эту ошибку, когда коллекция, которую вы пытаетесь перебрать, загружается медленно (IQueriable).
Преобразование коллекции IQueriable в другую перечислимую коллекцию решит эту проблему. пример
Примечание: .ToList () создает новый набор каждый раз, и это может вызвать проблемы с производительностью, если вы имеете дело с большими данными.
источник
SELECT COUNT(*) FROM Users
= 5Я решил проблему легко (прагматично), добавив опцию в конструктор. Таким образом, я использую это только при необходимости.
источник
Попробуйте в строке подключения установить
MultipleActiveResultSets=true
. Это позволяет многозадачность в базе данных.Это работает для меня ... будь то ваше соединение в app.config или вы установили его программно ... надеюсь, это полезно
источник
Первоначально я решил использовать статическое поле в своем классе API для ссылки на экземпляр объекта MyDataContext (где MyDataContext - это объект контекста EF5), но именно это, похоже, и создало проблему. Я добавил код, похожий на следующий, в каждый из моих методов API, и это устранило проблему.
Как утверждают другие люди, объекты EF Data Context НЕ являются поточно-ориентированными. Таким образом, размещение их в статическом объекте в конечном итоге приведет к ошибке «чтения данных» при правильных условиях.
Мое первоначальное предположение заключалось в том, что создание только одного экземпляра объекта будет более эффективным и позволит лучше управлять памятью. Из того, что я собрал, исследуя эту проблему, дело не в этом. Фактически, кажется более эффективным рассматривать каждый вызов вашего API как изолированное, поточно-ориентированное событие. Обеспечение правильного освобождения всех ресурсов, так как объект выходит из области видимости.
Это имеет смысл, особенно если вы переходите от своего API к следующему естественному прогрессу, который будет представлять его как API-интерфейс WebService или REST.
раскрытие
источник
Я заметил, что эта ошибка происходит, когда я отправляю IQueriable в представление и использую его в двойном foreach, где внутренний foreach также должен использовать соединение. Простой пример (ViewBag.parents может быть IQueriable или DbSet):
Простое решение - использовать
.ToList()
коллекцию перед ее использованием. Также обратите внимание, что MARS не работает с MySQL.источник
ToList()
на свой первый звонок, чтобы получить коллекцию из БД. Затем я сделал вforeach
этом списке, и последующие вызовы работали отлично, вместо того, чтобы выдавать ошибку.Я обнаружил, что у меня была та же ошибка, и это произошло, когда я использовал
Func<TEntity, bool>
вместоExpression<Func<TEntity, bool>>
вашего вместоpredicate
.После того, как я изменил из всех ,
Func's
чтобыExpression's
за исключением заканчивалось выброшен.Я считаю, что
EntityFramwork
делает некоторые умные вещи, сExpression's
которыми он просто не делает сFunc's
источник
(MyTParent model, Func<MyTChildren, bool> func)
так, чтобы мои ViewModels могли указать определенноеwhere
предложение к методу Generic DataContext. Ничего не работало, пока я не сделал это.2 решения для смягчения этой проблемы:
.ToList()
после вашего запроса, чтобы вы могли затем выполнить итерацию по нему, открывая новый DataReader..Include
(/ дополнительные объекты, которые вы хотите загрузить в запросе /) это называется активной загрузкой, которая позволяет (действительно) включать связанные объекты (объекты) во время выполнения запроса с помощью DataReader.источник
Хорошим промежуточным положением между включением MARS и извлечением всего результирующего набора в память является получение только идентификаторов в начальном запросе, а затем цикл по идентификаторам, материализующим каждую сущность на ходу.
Например (используя примеры сущностей «Блог и сообщения», как в этом ответе ):
Это означает, что вы вытягиваете в память только несколько тысяч целых чисел, а не тысячи целых графов объектов, что должно минимизировать использование памяти, позволяя вам работать по элементам без включения MARS.
Еще одно приятное преимущество этого, как видно из примера, заключается в том, что вы можете сохранять изменения во время цикла по каждому элементу, вместо того, чтобы ждать до конца цикла (или другого подобного обходного пути), как это потребуется даже при MARS включен (см. Здесь и здесь ).
источник
context.SaveChanges();
Внутренний цикл :(. Это не хорошо. Он должен быть за пределами цикла.В моем случае я обнаружил, что до вызова myContext.SaveChangesAsync () отсутствовали операторы «await». Добавление ожидания до того, как эти асинхронные вызовы исправили проблемы со считывателем данных для меня.
источник
Если мы попытаемся сгруппировать часть наших условий в метод Func <> или расширение, мы получим эту ошибку, предположим, у нас есть код, подобный этому:
Это вызовет исключение, если мы попытаемся использовать его в Where (), вместо этого нам нужно создать предикат следующим образом:
Более подробную информацию можно прочитать по адресу: http://www.albahari.com/nutshell/predicatebuilder.aspx.
источник
Эта проблема может быть решена просто путем преобразования данных в список
источник
В моей ситуации проблема возникла из-за регистрации внедрения зависимости. Я внедрял службу области запроса для каждого запроса, которая использовала dbcontext, в зарегистрированную службу синглтона. Для этого dbcontext был использован в нескольких запросах и, следовательно, ошибка.
источник
В моем случае проблема не имела ничего общего со строкой соединения MARS, а с сериализацией json. После обновления моего проекта с NetCore2 до 3 я получил эту ошибку.
Более подробную информацию можно найти здесь
источник
Я решил эту проблему, используя следующий раздел кода перед вторым запросом:
Вы можете изменить время сна в миллисекундах
PD Полезно при использовании потоков
источник