Подтвердить что ты не робот

Получает ли объекты с AsNoTracking() отключить автоматический вызов DetectChanges()?

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

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

Context.Configuration.AutoDetectChangesEnabled = false;

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

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

Ответ 1

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

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

или что [установка AutoDetectChangesEnabled] должно выполняться явно

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

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

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

  • AsNoTracking отлично, если вы хотите получать данные только для чтения. Он не имеет побочных эффектов (как в: его эффект ясен).
  • Настройка AutoDetectChangesEnabled = false останавливает автоматические вызовы DetectChanges (которые могут быть многочисленными), но имеет побочные эффекты, о которых вам нужно знать. Из книги Лермана и Миллера DbContext:

    Разработка, когда DetectChanges нужно вызывать, не так тривиальна, как она может появиться. Команда Entity Framework настоятельно рекомендует вам только свопинг для ручного вызова DetectChanges, если вы испытываете проблемы с производительностью. Кроме того, рекомендуется также отказаться от автоматического DetectChanges для плохо выполняемых разделов кода и для его повторного использования как только этот раздел закончит выполнение.

Ответ 2

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

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

Итак, по крайней мере для нас, были огромные выгоды, которые можно было сделать, установив его ложным. Мы используем шаблон "Единица работы", и мы явно указываем, является ли Единица работы "только для чтения" или нет. Для единицы работы только для чтения установка AutoDetectChangesEnabled = false совершенно безопасна, так как никогда не будет никаких изменений. Фактически, мы добавили это изменение в нашу систему через два года после нашего первоначального выпуска (так было много, много ранее существовавших блоков работ в коде), и это изменение ничего не сломало и значительно улучшило производительность.

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

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

  • У нас есть подкласс DBContext, который обеспечивает большую часть инфраструктуры для нашей единицы работы.
  • Наша единица работы - это в основном облегченная оболочка вокруг контекста.
  • Когда выделяется единица работы (обычно в блоке использования), она получает один из этих контекстов посредством инъекции (мы используем Castle/Windsor)
  • Во время инициализации единица работы вызывает метод в контексте, который устанавливает AutoDetectChangesEnabled в false
  • В настоящее время мы делаем это все время, потому что мы всегда используем прокси-серверы обнаружения изменений, и они не требуют AutoDetectChangesEnabled
  • Раньше мы делали это только для единиц "только для чтения", так как если в UoW ничего не было изменено, нет необходимости обнаруживать изменения (когда мы выделили единицу работы, мы явно указываем, является ли она доступной только для чтения или нет)  -