Платформа Entity Framework и пул соединений

Недавно я начал использовать Entity Framework 4.0 в своем приложении .NET 4.0, и мне интересно узнать несколько вещей, связанных с объединением.

  • Пул соединений, как мне известно, управляется поставщиком данных ADO.NET, в моем случае с сервером MS SQL. Это применимо, когда вы создаете экземпляр контекста новых объектов (ObjectContext), то есть без параметров new MyDatabaseModelEntities()?

  • Каковы преимущества и недостатки a) создания контекста глобальных сущностей для приложения (т.е. одного статического экземпляра) или б) создания и экспонирования контекста сущностей для каждой данной операции/метода с помощью using блок.

  • Любые другие рекомендации, рекомендации или общие подходы к определенным сценариям, о которых я должен знать?

Ответ 1

  • Пул соединений обрабатывается как в любом другом приложении ADO.NET. Соединение с сущностью по-прежнему использует традиционное соединение с традиционной цепочкой соединений. Я считаю, что вы можете отключить пул соединений в строке соединения, если вы не хотите его использовать. (подробнее о Пул соединений SQL Server (ADO.NET))
  • Никогда не используйте глобальный контекст. ObjectContext внутренне реализует несколько шаблонов, включая Identity Map и Unit of Work. Воздействие использования глобального контекста различно для каждого типа приложения.
  • Для веб-приложений используется один контекст для каждого запроса. Для веб-служб используется один контекст для каждого звонка. В приложениях WinForms или WPF используйте единый контекст для каждой формы или для ведущего. Могут быть некоторые особые требования, которые не позволят использовать этот подход, но в большинстве случаев этого достаточно.

Если вы хотите знать, какое влияние имеет контекст одного объекта для приложения WPF/WinForm, проверьте эту статью . Речь идет о сеансе NHibernate, но идея такая же.

Edit:

Когда вы используете EF, он по умолчанию загружает каждый объект только один раз для каждого контекста. Первый запрос создает объект instace и сохраняет его внутри. Любой последующий запрос, требующий сущности с тем же ключом, возвращает этот сохраненный экземпляр. Если значения в хранилище данных изменились, вы все равно получаете объект со значениями из исходного запроса. Это называется образ карты идентификации. Вы можете заставить контекст объекта перезагрузить объект, но он перезагрузит один общий экземпляр.

Любые изменения, внесенные в объект, не сохраняются, пока вы не вызываете SaveChanges в контексте. Вы можете делать изменения в нескольких объектах и ​​хранить их сразу. Это называется Структурой работы. Вы не можете выборочно указать, какой измененный прикрепленный объект вы хотите сохранить.

Объедините эти два шаблона, и вы увидите некоторые интересные эффекты. У вас есть только один экземпляр объекта для всего приложения. Любые изменения в объекте влияют на все приложение, даже если изменения еще не сохранены (совершены). В большинстве случаев это не то, что вы хотите. Предположим, что у вас есть форма редактирования в приложении WPF. Вы работаете с сущностью, и вы решаете отменить комплексное редактирование (изменение значений, добавление связанных объектов, удаление других связанных объектов и т.д.). Но объект уже изменен в общем контексте. Что вы будете делать? Подсказка: я не знаю ни о каких CancelChanges или UndoChanges на ObjectContext.

Я думаю, нам не нужно обсуждать сценарий сервера. Простое совместное использование единого объекта среди нескольких HTTP-запросов или вызовов веб-служб делает ваше приложение бесполезным. Любой запрос может просто запускать SaveChanges и сохранять частичные данные из другого запроса, потому что вы используете единую единицу работы среди всех из них. Это также будет иметь другую проблему: контекст и любые манипуляции с сущностями в контексте или соединение с базой данных, используемое контекстом, не являются потокобезопасными.

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

Ответ 2

По словам Даниэля Симмонса:

Создайте новый экземпляр ObjectContext в Оператор Use для каждой службы чтобы он был утилизирован перед возвратом метода. Этот шаг имеет решающее значение для масштабируемости вашего сервиса. Он гарантирует, что соединения с базой данных не будут открыты для всех вызовов службы, а это временное состояние, используемое конкретной операцией, - это сбор мусора, когда эта операция завершена. Entity Framework автоматически кэширует метаданные и другую необходимую им информацию в домене приложения, а ADO.NET объединяет соединения с базой данных, поэтому повторное создание контекста каждый раз является быстрой операцией.

Это из его всеобъемлющей статьи здесь:

http://msdn.microsoft.com/en-us/magazine/ee335715.aspx

Я считаю, что этот совет распространяется на HTTP-запросы, поэтому он будет действителен для ASP.NET. Однопользовательское приложение с жир-клиентом, такое как приложение WPF, может быть единственным случаем для "общего" контекста.

Ответ 3

В дополнение к документации EF6 (4,5): https://msdn.microsoft.com/en-us/data/hh949853#9

9.3 Контекст на запрос

Контексты Entity Frameworks предназначены для использования в качестве недолговечных экземпляров, чтобы обеспечить наиболее оптимальный уровень производительности. Предполагается, что контексты будут недолговечными и отброшены, и как таковые были реализованы, чтобы быть очень легкими и повторно использовать метаданные, когда это возможно. В веб-сценариях важно помнить об этом и не иметь контекста больше, чем продолжительность одного запроса. Аналогично, в сценариях, отличных от веб-сайтов, контекст должен быть отброшен на основе вашего понимания различных уровней кэширования в Entity Framework. Вообще говоря, следует избегать использования экземпляра контекста на протяжении всего срока службы приложения, а также контекстов для потока и статических контекстов.

Ответ 4

Ниже код помог моему объекту обновиться со свежими значениями базы данных. Команда Entry (object).Reload() заставляет объект вызывать значения базы данных

GM_MEMBERS member = DatabaseObjectContext.GM_MEMBERS.FirstOrDefault(p => p.Username == username && p.ApplicationName == this.ApplicationName);
DatabaseObjectContext.Entry(member).Reload();