2010-09-06 3 views
239

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

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

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

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

ответ

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

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

Edit:

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

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

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

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

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

+0

Спасибо за ваш ответ. Возможно, вы могли бы объяснить, почему плохо использовать один глобальный контекст? Это делает параллельный доступ сложнее, конечно, но что еще ...? – Noldorin

+0

Хорошо, теперь намного яснее, спасибо. Просто чтобы подтвердить, хотя глобальный контекст никогда не подходит, может быть, что один контекст для «диалогового окна редактирования» или такого может быть правильным? В других ситуациях, таких как веб-службы и ASP.NET, контексты внутри методов имеют смысл. О правильном? – Noldorin

+0

Я принял ваш совет и удалил singelton. Теперь я получаю еще одну ошибку: http://stackoverflow.com/questions/14795899/an-entity-object-cannot-be-referenced-by-multiple-instances-of-ientitychangetrac –

61

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

Create a new ObjectContext instance in a Using statement for each service method so that it is disposed of before the method returns. This step is critical for scalability of your service. It makes sure that database connections are not kept open across service calls and that temporary state used by a particular operation is garbage collected when that operation is over. The Entity Framework automatically caches metadata and other information it needs in the app domain, and ADO.NET pools database connections, so re-creating the context each time is a quick operation.

Это из его содержательных статей здесь:

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

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

+0

Спасибо, это очень информативная цитата. Тем не менее, мне все еще интересно, будет ли общий (глобальный) контекст подходящим даже для клиентского приложения WPF или такого. Есть ли какое-либо * преимущество даже в этом случае? – Noldorin

+0

Не было бы никакого преимущества для глобального контекста в приложении WPF, но, вероятно, также не было бы значительного ущерба. Если вы реализуете глобальный контекст, вам может потребоваться выполнить ручное управление соединениями с базой данных (явное закрытие соединения) в случаях высоких запросов. –

+1

Право; так что по существу я никогда не ошибаюсь, используя несколько временных контекстов (учитывая, что я знаю, что происходит объединение пулов)? ... Если вы использовали единый глобальный контекст, не могли ли теоретическое падение теории в определенный момент времени? – Noldorin

2

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

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

, а также для коллекций (код VB): 'CType (myContext, IObjectContextAdapter) .ObjectContext.Refresh (RefreshMode.StoreWins, myCustomers)' –

6

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

9,3 Контекст по запросу

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

+0

Я знаю, что этот ответ был здесь некоторое время, но я должен сказать, что это спасло меня тонна головной боли. При использовании EF с Oracle, возникла ошибка «Объединенное соединение» и не могла понять, почему. Я установил dbContext как переменную класса, создав его при создании. Меняя его на создание контекста по мере необходимости, фиксировали все болезни моего мира. Спасибо! – Fletchius