Обновление 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.