DbContext ChangeTracking убивает производительность?

Я занимаюсь обновлением приложения с EF1 до EF4.1. Я создал DbContext и набор POCO, используя шаблоны «ADO.NET DbContext Generator».

Когда я запрашиваю сгенерированный DbContext, выполнение части запроса базы данных занимает 4 мс (проверено с помощью EF Profiler). Затем контексту требуется около 40 секунд (словами: СОРОК!) на то, чтобы сделать все, что он делает, прежде чем он вернет результат в приложение.

EF1 обрабатывает тот же запрос менее чем за 2 секунды.

Отключение AutoDetectChanges, LazyLoading и ProxyGeneration выигрывает у меня 2-3 секунды.

Когда я использую метод расширения AsNoTracking(), я могу сократить общее время выполнения примерно до 3 секунд.

Это указывает на то, что ChangeTracking является виновником.

Но ChangeTracking — это то, что мне нужно. Я должен иметь возможность в конечном итоге сохранить все изменения, не выбирая вручную, какие объекты были изменены.

Любые идеи, как я могу решить эту проблему с производительностью?


person Sebastian Weber    schedule 12.05.2011    source источник
comment
Здесь обсуждалось несколько раз. Похоже на ошибку в EFv4.1   -  person Ladislav Mrnka    schedule 12.05.2011
comment
Еще хуже, когда я использую EF4.0 и шаблон генератора сущностей ADO.NET POCO. Затем требуется более 80 секунд, пока я не получу какой-либо результат. Таким образом, ошибка была еще более серьезной в предыдущей версии, и MS не смогла правильно исправить ее в EF4.1?   -  person Sebastian Weber    schedule 12.05.2011
comment
Вы можете попробовать отключить AutoDetectChanges / использовать AsNoTracking, но при этом создать трекинговые прокси (все свойства должны быть виртуальными). Интересно, меняется ли этот трек или нет, и я не могу проверить это сам сейчас.   -  person Ladislav Mrnka    schedule 12.05.2011
comment
Вы даже не можете запустить запрос. Вы получаете исключение, которое говорит вам, что свойство не может быть установлено, поскольку ему уже присвоено значение типа EntityCollection, как только я изменяю шаблон T4, чтобы сделать каждое свойство виртуальным.   -  person Sebastian Weber    schedule 12.05.2011
comment
Как вы создавали сущности? Эта ошибка говорит о том, что вы пытаетесь установить для коллекции свойство навигации, которое уже инициализировано EntityCollection.   -  person Ladislav Mrnka    schedule 12.05.2011
comment
Как я уже сказал: я изменил шаблон T4 для модели, чтобы сделать каждое общедоступное свойство виртуальным. Вот и все. Больше ничего. Ошибка возникает в конструкторе сгенерированного объекта, где он пытается инициализировать свойства навигации с помощью HashSets. Я предполагаю, что прокси-сервер уже установил эти свойства на что-то другое. Но я не знаю, почему создание виртуальных свойств примитивов мешает свойствам навигации.   -  person Sebastian Weber    schedule 12.05.2011
comment
Я вижу, что вы также задали этот вопрос на форуме MSDN. Добавьте сведения о том, что он также плохо работает при использовании EFv4 с POCO.   -  person Ladislav Mrnka    schedule 12.05.2011
comment
Изменение шаблона T4 таким образом, чтобы ctor инициализировал свойства навигации только тогда, когда они все еще имеют значение NULL, решило проблему с исключением. Но ChangeTracking не работает, и SaveChanges() не сохраняет никаких изменений.   -  person Sebastian Weber    schedule 12.05.2011
comment
насколько велик и сложен ваш набор результатов?   -  person Alexandre Brisebois    schedule 08.06.2011
comment
Пометил все свойства как виртуальные?   -  person BennyM    schedule 18.07.2011
comment
Я надеюсь, что ваш интерфейс к EF4 (или, в частности, ваш репозиторий данных) был абстрагирован в один проект с фактической реализацией в другом проекте. У меня те же проблемы, и я так близок к переходу на NHibernate 3.   -  person 37Stars    schedule 30.08.2011
comment
Выполняется ли этот запрос в совершенно новом контексте?   -  person ladenedge    schedule 31.08.2011
comment
@ Программисты, у которых возникли проблемы с их навигационными свойствами, сделали виртуальные попытки с ProxyGeneration = true: не создавать экземпляры и не назначать какую-либо коллекцию. Об этом позаботится генерация прокси. Однако, чтобы получить свой прокси-объект, вам нужно создать его с помощью DbSet.Create. Простого создания экземпляра с помощью new будет недостаточно.   -  person Alex Maker    schedule 01.09.2011


Ответы (2)


Приведена ли техника в конце этой документации полезно? В качестве альтернативы я избежал многих ошибок производительности, используя гибкий интерфейс для декларативного указания, какие сущности в данной транзакции точно не изменятся, а какие могут измениться (неизменяемые или неизменяемые). Например, если объекты, которые я сохраняю, являются сводными корнями, в которых корень или его объекты ссылаются на элементы "refdata", то эта эвристика предотвращает множество операций записи, поскольку неизменяемые элементы не нужно отслеживать. . Все изменяемые элементы записываются без проверки (слабость... та, которая может быть приемлемой или неприемлемой).

Я использую это с общим шаблоном репозитория именно потому, что не хочу отслеживать изменения или реализовывать конкретную стратегию для каждого случая. Если этого недостаточно, возможно, сработает собственное отслеживание изменений вне контекста и добавление сущностей по мере необходимости.

person Kit    schedule 09.09.2011

Не видя запроса, я не могу точно сказать, в чем может быть проблема. Может ли это быть связано?

Почему оператор Contains() ухудшает работу Entity Framework? производительность настолько резко?

В зависимости от используемых операторов LINQ кажется, что EF с трудом преобразовывает некоторые запросы в SQL. Может быть, вы столкнулись с подобной ситуацией здесь.

person Mike    schedule 09.11.2011