Обновление Entity Framework до 6.2.0 из 6.1.x прерывает определенные запросы, если я не включу MARS
Недавно я обновил EF 6.1.3 до 6.2.0 на одном из наших крупных проектов, и он нарушил значительное количество наших запросов LINQ. Включение MultipleActiveResultSets заставляет все работать нормально, но я изо всех сил пытаюсь понять изменения. Мы используем EF уже много лет и без каких-либо проблем прошли несколько крупных изменений. Если я просто вернусь к 6.1.3, все будет работать так же, как ожидалось, - на самом деле все работает, даже если я явно отключу MARS в 6.1.3.
Позвольте мне привести несколько упрощенных примеров. Первая проблема связана с вложенными запросами:
foreach(var row in dbSet.Where(<condition>))
foreach(var innerRow in otherDbSet.Where(_ => _.Property == row.Property))
Это отлично работает в 6.1.3, но в 6.2.0 выбрасывается исключение "Есть уже открытый DataReader...". Я понимаю природу исключения, и я могу решить это, вызвав ToList() во внешнем запросе, чтобы сначала перенести результаты в память - я не понимаю, почему я не должен был этого делать в 6.1.3 (даже при отключенном MARS). Не всегда желательно просто загрузить весь внешний набор в память.
Это также похоже на ленивые свойства. Например, мы создаем ComboBoxes из простых запросов, таких как:
return db.Collection
.Where(<condition>)
.AsEnumerable()
.Select(_ => new ListItem(_.Id, _.LazyNavigationProperty.Description))
.ToList();
Это отлично работает в 6.1.3, но опять же в 6.2.0 выбрасывается исключение "Есть уже открытое DataReader...". Исправление - теперь мне нужно с нетерпением загрузить свойство навигации.
В конечном счете у меня нет явного вопроса, я просто пытаюсь понять, почему незначительное обновление версии, по-видимому, вызвало серьезные нарушения изменений в обработке запросов.
Двигаясь вперед, это влияет на слишком много запросов для рефакторинга. Когда я изучал проблему, я увидел смутные предупреждения о возможности MARS, но никто не дал ничего конкретного. Есть ли веская причина не включать его?
Ответы
Ответ 1
Вы получаете эту ошибку, потому что вы перебираете набор результатов, пытаясь открыть другой набор результатов (пока первый еще не закончил) → своего рода отложенная загрузка (первая "для каждой" итерации в вашем случае) → Есть много способов решить эту проблему, как вы уже видели сами: использовать toList (сначала перенести в память), потому что он больше не использует средство чтения данных для открытия набора.
похоже, это МОЖЕТ быть связано с исправлением ошибки в 6.2 (примечания к выпуску: https://entityframework.net/ef-version-history) - похоже, связано с: "Ошибка: повторные попытки запросов или SQL-команд завершаются неудачно с помощью" The SqlParameter " уже содержится в другой SqlParameterCollection. ")
Относительно включения MARS: вы можете найти специальное предупреждение здесь:
https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql/enabling-multiple-active-result-sets
Ответ 2
Entity Framework
должен предоставить крошечную абстракцию вашей модели базы данных.
Такая работа требует выполнения нескольких запросов под капотом. Механизм может также потребовать больше запросов, необходимых по сравнению с той же рабочей нагрузкой, закодированной вручную.
Это физиологическая эволюция, позволяющая обрабатывать все возможные запросы пользователей. Простое обновление до другой версии Entity Framework
может привести к различиям в рабочей нагрузке базы данных, создаваемой внутренним оборудованием.
MARS
требуется, поскольку EF изменил способ поиска объекта (в частности, внутри циклов в сочетании с отложенной загрузкой). К сожалению, в большинстве случаев вам необходимо использовать MARS
при использовании Entity Framework.
В настоящее время использование async/await
обычно требует и MARS
.