Отключает ли получение сущностей с помощью AsNoTracking() автоматический вызов DetectChanges()?

Я познакомился с этой концепцией AsNoTracking(), DetectChanges() и AutoDetectChangesEnabled совсем недавно. Я понимаю, что при извлечении записей из базы данных через Entity Framework с использованием AsNoTracking() Entity Framework не отслеживает никаких изменений в этих записях, и в этом случае обновление любого свойства извлеченной записи не удастся.

Мой вопрос заключается в том, что если записи извлекаются таким образом, это также приведет к отключению автоматического вызова DetectChanges() или это нужно сделать явно, установив:

Context.Configuration.AutoDetectChangesEnabled = false;

Также любезно дайте мне знать, какое влияние (с точки зрения производительности) это имеет, если оба действия выполняются при извлечении данных строго только для чтения:

Context.Configuration.AutoDetectChangesEnabled = false;
Context.Set<T>().AsNoTracking();

person Sayan Pal    schedule 08.01.2014    source источник


Ответы (2)


это также приведет к отключению автоматического вызова DetectChanges()

Нет, не будет. Но вы должны понимать, что AsNoTracking и DetectChanges не имеют ничего общего друг с другом (кроме того, что они являются частью EF). Объекты, полученные с помощью AsNoTracking, в любом случае никогда не обнаружат изменений, независимо от того, включена функция AutoDetectChanges или нет. Кроме того, AsNoTracking работает на уровне DbSet, AutoDetectChangesEnabled на уровне контекста. Было бы плохо, если бы метод DbSet влиял на весь контекст.

или что [настройка AutoDetectChangesEnabled] должна быть выполнена явно

Ну, наверное, просто не стоит отключать AutoDetectChanges. Если вы это делаете, вы должны знать, что делаете.

какое влияние (с точки зрения производительности) он оказывает, если выполняются оба действия

Как говорится, они не связаны. Они оба могут улучшить производительность по-своему.

  • AsNoTracking отлично подходит, если вы хотите получать данные только для чтения. У него нет побочных эффектов (как в: его эффект очевиден)
  • #P7# <блочная цитата> #P8#
person Gert Arnold    schedule 08.01.2014
comment
Спасибо Герт за разъяснение концепции. Было бы безопасно заявить/предполагать, что когда набор записей извлекается с помощью структуры сущностей AsNoTracking(), он не вызывает DetectChanges() для этого конкретного набора записей? - person Sayan Pal; 12.01.2014
comment
Также важно подчеркнуть, что для сущностей, полученных с помощью AsNoTracking(), даже ручные вызовы DetectChanges() не обнаружат изменений в этих объектах. Они полностью оторваны от контекста. - person Doug; 14.01.2016
comment
Что касается «выяснения того, когда необходимо вызвать DetectChanges», если вы используете прокси-серверы отслеживания изменений, то вам фактически не нужно это решать, потому что прокси-серверы отслеживания изменений обрабатывают отслеживание изменений с большим трудом. -grain level (который не оказывает такого же влияния на производительность, как DetectChanges). Прокси-серверы имеют собственные накладные расходы, поэтому это зависит от характера вашего приложения, но мы используем прокси-серверы отслеживания изменений в сочетании с AutoDetectChanges = false, и это сработало хорошо. - person Terry Coatta; 05.03.2016

Мы обнаружили, что параметр AutoDetectChangesEnabled = false может иметь существенное (т.е. в 10 раз) влияние на производительность.

Общие сведения. Наша система полностью состоит из объектов модели EF, в которых используются прокси-серверы для обнаружения изменений. То есть все наши поля БД и реляционные свойства объявляются виртуальными. У нас также есть относительно глубоко структурированная объектная модель. То есть объект A содержит набор объектов B, которые, в свою очередь, содержат набор объектов C и т. д. Мы заметили, что создание нетривиального (> 100) числа этих объектов с помощью запроса EF/LINQ обходится дорого. Например, в одном случае для создания 250 объектов потребовалось около 2 секунд. Мы также заметили, что для создания экземпляра той же структуры, но с использованием анонимных объектов вместо этого требуется около 25 мс. Наконец, мы заметили, что если мы установим AutoDetectChangesEnabled = false, мы сможем использовать запрос, создающий объекты модели EF, и материализация снова займет около 25 мс.

Так что, по крайней мере, для нас было огромным преимуществом, если бы оно было ложным. Мы используем шаблон Unit Of Work и явно указываем, доступна ли Unit of Work только для чтения или нет. Для единицы работы, доступной только для чтения, установка AutoDetectChangesEnabled = false совершенно безопасна, так как никогда не будет никаких изменений. На самом деле, мы добавили это изменение в нашу систему через два года после нашего первоначального релиза (поэтому в коде было много-много ранее существовавших единиц работы), и это изменение вообще ничего не сломало, а значительно улучшило производительность.

Мы также поэкспериментировали с AsNoTracking() и обнаружили, что это практически не дает нам никакого прироста производительности. Насколько я понимаю, запрос с AsNoTracking() означает, что объекты не будут помещены в карту идентификаторов, и это заставит EF повторно выбрать объект с диска, если на него ссылаются более одного раза в контексте (например, в разных запросах ). Так что у AsNoTracking() есть некоторый потенциальный недостаток.

Сведения о реализации:

  • У нас есть подкласс DBContext, который обеспечивает большую часть инфраструктуры для нашей единицы работы.
  • Наша единица работы — это, по сути, легкая обертка вокруг контекста.
  • Когда единица работы выделяется (обычно в блоке using), она получает один из этих контекстов посредством внедрения (мы используем Castle/Windsor).
  • Во время инициализации единица работы вызывает метод контекста, для которого AutoDetectChangesEnabled устанавливается в false.
  • В настоящее время мы делаем это постоянно, потому что мы всегда используем прокси-серверы для обнаружения изменений, и они не требуют AutoDetectChangesEnabled.
  • Раньше мы делали это только для единиц работы «только для чтения», поскольку, если в UoW ничего не изменяется, нет необходимости обнаруживать изменения (когда мы выделяем единицу работы, мы явно указываем, доступна ли она только для чтения или нет)
  • -
person Terry Coatta    schedule 28.02.2014
comment
спасибо за этот замечательный ответ, есть ли шанс обновить ответ, чтобы показать, как вы включаете и отключаете AutoDetectChangesEnabled в своем UoW? У нас также есть UoW, и я пытался выяснить, как мне добиться именно того, что вы описали. - person leen3o; 10.09.2015
comment
На самом деле, мы отключаем отслеживание изменений в нашем классе, который обертывает DbContext. Мы делаем это, потому что используем прокси-серверы отслеживания изменений везде, поэтому отслеживание изменений никогда не требуется (в основном оно встроено в сгенерированные классы прокси-серверов). В DBContext всего одна строка кода: this.Configuration.AutoDetectChangesEnabled = false; - person Terry Coatta; 05.03.2016
comment
AsNoTracking иногда может иметь негативный эффект: stackoverflow. com/questions/9259480/ - person Arvand; 19.02.2017