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

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

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

Context.Configuration.AutoDetectChangesEnabled = false;

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

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

2 ответов


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

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

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

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

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

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

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

    разработка, когда DetectChanges должен быть вызван не так тривиально, как это может появиться. Группа Entity Framework настоятельно рекомендует только swap для ручного вызова DetectChanges, если вы испытываете проблема производительности. Также рекомендуется отказаться от автоматического Метод detectchanges для проблемных участков кода и включить его как только данный раздел будет завершен.


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

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

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

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

Детали Реализации:

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