Узагальнене сховище З EF 4.1 в чому сенс


145

Коли я заглиблююсь у DbContext, DbSet та пов'язані з ними інтерфейси, мені цікаво, чому вам потрібно впроваджувати окремий "Загальний" сховище навколо цих реалізацій?

Схоже, що DbContext і IDbSet роблять все необхідне і включають "Unit of Work" всередині DbContext.

Чи щось мені тут не вистачає, чи здається, що люди із задоволенням додають ще один шар залежності без причини.


Це трохи спірне / на основі думки питання. Я обговорював це тут .
Аміт Джоші

Відповіді:


202

Ви насправді праві. DbContextє реалізацією схеми одиниці роботи і IDbSetє реалізацією шаблону сховища.

Зараз сховища дуже популярні та використовуються. Усі користуються ними лише тому, що є десятки статей про створення репозиторію для сутності, але насправді ніхто не описує труднощів, пов'язаних з цим рішенням.

Основні причини використання сховища зазвичай:

  • Сховати EF від верхнього шару
  • Зробіть код краще перевіреним

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

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

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

Я слідкую за блогом Айенде . Якщо ви коли-небудь використовували NHibernate, ви, напевно, знаєте його статті. Нещодавно цей хлопець написав декілька статей проти використання сховища з NHibernate, але NHibernate набагато краще піддається макетуванню.


3
Ви можете знущатися з того, що IDbSetви можете також визначити спеціальний інтерфейс у похідному контексті, але це все. Після того, як ваш код використовує ChangeTracker, записи або що-небудь ще, для його завершення знадобиться велике зусилля.
Ладислав Мрнка

1
Так, EF - це не дуже орієнтований на ефективність інструмент. Принаймні, у МС є чимало можливостей зробити це кращим у майбутніх версіях.
Ladislav Mrnka

2
@chiccodoro: Правильно. Але як тільки ваш глузливий клас виставляє IQueryableабо приймає Expression<>як параметр, який внутрішньо ставиться до запиту Linq-to-Entities, ви визначаєте логіку поза компонентами, що знущаються, з побічними ефектами, які неможливо перевірити одиничними тестами.
Ладислав Мрнка

8
Якщо я використовую DbSet і BdContext прямо там, у своєму бізнес-шарі, я повинен посилатися на EntityFramework.dll там, а також у проекті DataLayer. Це одне мені каже, що йому потрібно якесь обгортання.
Ingó Vals

2
downvote: неповне - абстрагування EF за інтерфейсом сховища може зробити такий самий код клієнта, як в SL, так і в WPF.
h.alex

21

Я борюся з тими ж проблемами, і мобільність для одиничного тестування шарів EF важлива. Але я зіткнувся з цією чудовою статтею, яка пояснює, як налаштувати EF 4.1 DbContext для макерування, переконавшись, що ваш похідний DbContext реалізував загальний інтерфейс та відкриває IDbSet, а не DbSet. Оскільки я використовую перший підхід до бази даних, оскільки наша база даних вже існує, я просто змінив шаблони T4, які використовуються для створення мого похідного DbContext, щоб генерувати його для повернення інтерфейсів IDbSet, а також виходити з мого загального інтерфейсу. Таким чином, над усією справою можна легко знущатися, і вам не потрібно реалізовувати свій власний блок роботи або сховище. Просто напишіть свій службовий код, щоб споживати ваш загальний інтерфейс, і коли ви переходите до тестування,

http://refactorthis.wordpress.com/2011/05/31/mock-faking-dbcontext-in-entity-framework-4-1-with-a-generic-repository/


5

Однією з причин створення репозиторію є те, що ви можете приховати реалізацію DBSet і DbContext, якщо вирішите перейти з EntityFramework до чогось іншого або навпаки.

Наприклад, я використовував NHibernate, і я загортав усі виклики до цього фрейму всередині моїх класів сховищ. Вони повертають IEnumerable за те, що їх отримання стає "загальним", і мої сховища мають стандартні операції CRUD (оновлення, видалення тощо). Я давно перейшов до Entity Framework. Роблячи це, мені не потрібно було нічого змінювати в моїх класах ViewModel або поза ним, оскільки вони вказували на моє сховище - мені потрібно було лише змінити внутрішню частину мого сховища. Це значно полегшило життя під час міграції.

(Я використовував NHibernate, тому що ми підключаємось до ISeries, і на той час не було рентабельних реалізацій із використанням EF з ISeries. Єдиний доступний - заплатити IBM $ 12 000 за їх DB2Connect)


"Практично" (що стосується приховування DBSet і DbContext), ви виявите, що вам не потрібно виставляти EF будь-яким споживачам (наприклад, якщо ви використовуєте DI), але вам потрібен інтерфейс, який розкриває властивості IDbSet <T> або перейдіть на крок далі і замість цього введіть усі свої властивості як IQueryable <T>, але мій погляд на те, що ви можете повністю приховати свою залежність від DbSet і DbContext. Операції CRUD можуть бути записані як методи розширення, ви можете написати кілька методів розширення для різних резервних магазинів. Однак ви не ховали б використовувати LINQ.
Шон Вілсон
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.