Рамка сутності та об'єднання підключень


268

Нещодавно я почав використовувати Entity Framework 4.0 в моєму додатку .NET 4.0 і мені цікаво кілька речей, що стосуються об'єднання.

  1. Пул з'єднання, як я знаю, керує постачальником даних ADO.NET, в моєму випадку - сервером MS SQL. Чи застосовується це, коли ви інстанціюєте новий контекст сутності ( ObjectContext), тобто параметр new MyDatabaseModelEntities()?

  2. Які переваги та недоліки a) створення глобального контексту сутності для програми (тобто одного статичного екземпляра) або b) створення та викриття контексту сутностей для кожної операції / методу з usingблоком.

  3. Будь-які інші рекомендації, найкращі практики чи загальні підходи для певних сценаріїв, про які я повинен знати?

Відповіді:


369
  1. Пул з'єднання обробляється, як і в будь-якому іншому додатку ADO.NET. Підключення сутності все ще використовує традиційне підключення до бази даних з традиційним рядком з'єднання. Я вважаю, що ви можете вимкнути об'єднання з'єднань у рядку з'єднання, якщо ви не хочете його використовувати. (докладніше про об'єднання підключення до SQL Server (ADO.NET) )
  2. Ніколи не використовуйте глобальний контекст. ObjectContext внутрішньо реалізує декілька моделей, включаючи карту ідентичності та блок роботи. Вплив використання глобального контексту відрізняється від типу програми.
  3. Для веб-додатків використовуйте один контекст на запит. Для веб-служб використовуйте єдиний контекст за виклик. У додатках WinForms або WPF використовуйте один контекст на форму чи на кожного презентатора. Можуть бути деякі особливі вимоги, які не дозволять використовувати цей підхід, але в більшості ситуацій цього достатньо.

Якщо ви хочете дізнатися, який вплив має один об'єктний контекст для програми WPF / WinForm, перегляньте цю статтю . Йдеться про сесію NHibernate, але ідея така ж.

Редагувати:

Якщо ви використовуєте EF, він за замовчуванням завантажує кожну сутність лише один раз у контексті. Перший запит створює об'єкт instace і зберігає його внутрішньо. Будь-який наступний запит, для якого потрібна сутність із тим самим ключем, повертає цей збережений екземпляр. Якщо значення в сховищі даних змінилися, ви все одно отримуєте об'єкт зі значеннями з початкового запиту. Це називається схемою карти ідентичності . Ви можете змусити контекст об'єкта перезавантажити об'єкт, але він перезавантажить один спільний екземпляр.

Будь-які зміни, внесені в сутність, не зберігаються, поки ви не зателефонуєте SaveChangesза контекст. Ви можете робити зміни в декількох об'єктах і зберігати їх одночасно. Це називається схемою одиниці роботи . Ви не можете вибірково сказати, яку модифіковану додану сутність ви хочете зберегти.

Комбінуйте ці два візерунки, і ви побачите кілька цікавих ефектів. У вас є лише один екземпляр сутності для всієї програми. Будь-які зміни сутності впливають на всю програму, навіть якщо зміни ще не зберігаються (здійснюються). У більшості випадків це не те, чого ти хочеш. Припустимо, у вас є форма редагування в додатку WPF. Ви працюєте з цією суттю і вирішуєте скасувати складне редагування (зміна значень, додавання пов'язаних об'єктів, видалення інших суміжних об'єктів тощо). Але сутність вже змінена в спільному контексті. Що ти робитимеш? Підказка. Я не знаю про будь-які відміни змін або скасування змін ObjectContext.

Я думаю, нам не доведеться обговорювати серверний сценарій. Просто обмін однією суттю між кількома запитами HTTP або викликами веб-служб робить вашу програму марною. Будь-який запит може просто викликати SaveChangesі зберегти часткові дані з іншого запиту, оскільки ви обмінюєтесь єдиною одиницею роботи між усіма ними. У цьому також буде інша проблема - контекст і будь-які маніпуляції з сутностями в контексті або підключення до бази даних, використовувані контекстом, не є безпечними для потоків.

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


Спасибі за Вашу відповідь. Можливо, ви могли б детальніше пояснити, чому погано використовувати єдиний глобальний контекст? Це впевнено робить паралельний доступ, але що ще ...?
Нолдорін

Гаразд, це зараз набагато зрозуміліше, дякую. Просто для підтвердження, хоча глобальний контекст ніколи насправді не підходить, єдиний контекст для "діалогу редагування" чи такий може бути правильним способом? В інших ситуаціях, як-от веб-сервіси та ASP.NET, контексти методів мають лише більше сенсу. Про правильне?
Нолдорін

Я прийняв вашу пораду і зняв сингелтон. Тепер я отримую ще одну помилку: stackoverflow.com/questions/14795899/…
Elad Benda

Я розумію, що реалізація схеми роботи блоку та інкапсуляція DbContext повинна розділяти ділову логіку та операції з базою даних. Я не в змозі зрозуміти, як реалізувати схему одиниці роботи та використовувати TransactionScope лише для деяких операцій.
Рудольф Дворачек

4
@RudolfDvoracek: Легко. TransactionScopeне належить до одиниці роботи, вона належить до вашої бізнес-логіки, оскільки сама логіка визначає транзакцію. Блок роботи визначає лише те, що слід зберігати разом, тоді як обсяг транзакцій дозволяє використовувати одиницю стійкості роботи кілька разів у межах однієї транзакції.
Ladislav Mrnka

70

За словами Даніеля Сіммонса:

Створіть новий екземпляр ObjectContext в операторі Using для кожного методу обслуговування, щоб він був утилізований до повернення методу. Цей крок має вирішальне значення для масштабованості вашої послуги. Він гарантує, що підключення до бази даних не залишаються відкритими для викликів служб, а тимчасовий стан, який використовується певною операцією, збирається сміттям, коли ця операція закінчена. Entity Framework автоматично кешує метадані та іншу необхідну йому інформацію в домені додатка та підключення баз даних ADO.NET, тому щоразу створюючи контекст, це швидка операція.

Це з його вичерпної статті тут:

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

Я вважаю, що ця порада поширюється на запити HTTP, тому буде дійсною для ASP.NET. Вкрай важливий для клієнтів додаток, наприклад, жир, наприклад, програма WPF, може бути єдиним випадком для "спільного" контексту.


Дякую, це дуже інформативна цитата. Однак мені все ще цікаво, чи буде спільний (глобальний) контекст підходящим навіть для клієнтського додатка WPF чи іншого. Чи є якась перевага навіть у цьому випадку?
Нолдорін

Не було б переваги перед глобальним контекстом у додатку WPF, але, ймовірно, не було б і суттєвого збитку. Якщо ви реалізуєте глобальний контекст, вам, можливо, доведеться виконати ручне керування підключеннями до бази даних (явне закриття з'єднання) у випадках високої швидкості запитів.
Дейв Сверський

1
Правильно; так що по суті я ніколи не можу помилитися, використовуючи кілька тимчасових контекстів (враховуючи, що я знаю, що відбувається об'єднання з'єднань)? ... Якби ви використовували єдиний глобальний контекст, чи не міг би теоретичний зв’язок впасти в випадковий момент часу?
Нолдорін

1
@Nolodrin: Я не думаю, що з'єднання впаде "випадковим чином" ... ризик полягає в тому, що з'єднання можуть бути відкритими занадто довго і насичувати пул з'єднань.
Дейв Сверський

1
Моя думка, реалізація ObjectContext / DbContext IDisposable, тому повинна бути відкритою протягом найкоротшого розумного часу.
nicodemus13

12

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

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

Контексти Entity Framework повинні використовуватися як короткочасні екземпляри, щоб забезпечити найбільш оптимальний досвід роботи . Очікується, що контексти будуть короткотривалими та відкинуті, і як такі вони були реалізовані як дуже легкі та використовувати метадані, коли це можливо. У веб-сценаріях важливо пам’ятати про це і не мати контексту більше, ніж тривалість одного запиту. Аналогічно, у несетевих сценаріях слід відкидати контекст на основі вашого розуміння різних рівнів кешування в Entity Framework. Взагалі кажучи, слід уникати наявності контекстного примірника протягом усього життя програми, а також контекстів на потоки та статичних контекстів.


2
Я знаю, що ця відповідь була деякий час, але я мушу сказати, що це врятувало мене тонни головного болю. Під час використання EF з Oracle утримується помилка "Об'єднане об'єднання", і не вдалося зрозуміти, чому. Я встановив dbContext як змінну класу, інстанціюючи його при створенні. Змінивши його на створення контексту за потребою, зафіксував усі негаразди мого світу. Дякую!
Флетхій

1

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

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

а також для колекцій (код VB):CType(myContext, IObjectContextAdapter).ObjectContext.Refresh(RefreshMode.StoreWins,myCustomers)
Іван Феррер Вілла,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.