Підводні камені дизайну, керованого доменом з Entity Framework


12

Багато навчальних посібників з DDD, який я вивчав, здебільшого охоплюють теорію. Всі вони мають рудиментарні приклади коду (Pluralsight та подібні).

В Інтернеті також є спроби кількох людей створити навчальні посібники, що охоплюють DDD за допомогою EF. Якщо ви почнете їх вивчати лише коротко - ви швидко помітите, що вони сильно відрізняються один від одного. Деякі люди рекомендують мінімізувати додаток та уникати введення додаткових шарів, наприклад, сховища поверх EF , інші, безперечно, генерують додаткові шари, часто навіть порушуючи SRP, вводячи DbContextв агрегатні корені.

Я жахливо вибачаюсь, якщо задаю питання, засновані на думці, але ...

Що стосується практики - Entity Framework - одна з найпотужніших та широко використовуваних ОРМ. На жаль, ви не знайдете комплексного курсу, що охоплює DDD.


Важливі аспекти:

  • Entity Framework виводить UoW & Repository ( DbSet) з коробки

  • з EF ваші моделі мають навігаційні властивості

  • з EF все моделей завжди доступний офф DbContext(вони представлені у вигляді DbSet)

Підводні камені:

  • ви не можете гарантувати, що ваші дочірні моделі впливають лише через агрегатний корінь - ваші моделі мають навігаційні властивості, і їх можна змінювати та дзвонитиdbContext.SaveChanges()

  • з DbContextви можете отримати доступ до кожної вашої моделі, таким чином обходячи агрегатний Root

  • Ви можете обмежити доступ до дітей кореневого об'єкта з допомогою ModelBuilderв OnModelCreatingметоді , позначивши їх як поля - я до сих пір не вірю , що це правильний шлях йти про DDD плюс це важко оцінити , які пригоди це може привести в майбутньому ( вельми скептично )

Конфлікти:

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

  • реалізуючи додатковий шар сховища, ми ігноруємо вбудовані функції EF (кожне DbSetвже є репо) та надмірно ускладнюємо додаток


Мій висновок:

Пробачте про моє незнання, але виходячи з вищенаведеної інформації - це або Entity Framework не є адекватним для дизайну, керованого доменом, або дизайн, керований доменом, є недосконалим і застарілим підходом.

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


Якщо я помиляюся - чи могла б хтось хоча б деталізувати простий набір інструкцій (або навіть надати пристойні приклади коду) про те, як рухатись щодо DDD з EF?


Я детально кроки тут в відповідності з моїм розумінням того , як EF працює. Проте ці кроки не вирішують проблеми доступу дітей до нав. властивості або за допомогою DbSets off DbContext.
Алекс Герман

Відповіді:


8

DDD і EF мало нічого спільного між собою.

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

EF - технологія стійкості. В основному це стосується записів даних та баз даних.

Ці двоє різко розлучені. Дизайн DDD може використовувати EF в якійсь формі під кришкою, але обидва не повинні взаємодіяти іншим чином.

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

Однак це тлумачення є хибним, і я б настійно рекомендував його повністю ігнорувати.

На закінчення : DDD та EF не є взаємовиключними, вони фактично не мають відношення один до одного, якщо ви займаєтесь належним об'єктним моделюванням, а не моделюванням даних. Об'єкти DDD не повинні в будь-якій формі або формі бути артефактами EF. Суб'єкти DDD, наприклад, не повинні бути "суб'єктами господарювання". Всередині якоїсь функції, що стосується бізнесу, дизайн DDD може використовувати EF з деякими пов'язаними об'єктами даних, але вони завжди повинні бути приховані під інтерфейсом, орієнтованим на поведінку.


1
EF просто - це економія часу. Відстеження змін та збереження агрегатів - це те, коли EF вже дуже допомагає. На жаль, наразі немає можливості визначити форму агрегатів на рівні конфігурації.
Павло Воронін

6

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

Я розумію, що EF продається як ярлик між доступом до бази даних та моделюванням доменів, однак цей підхід є суттєво недоліком, оскільки він вирішує дві проблеми, що пов'язані між собою. Були й інші спроби .NET змусити клас виконувати деякі абсолютно не пов'язані між собою речі (наприклад, .NET Remoting), і вони не закінчилися добре.

Робіть DDD за допомогою класів POCO і не дозволяйте схемі баз даних керувати вашим дизайном. Тримайте EF всередині шару сховища / стійкості та не дозволяйте суб'єктам EF просочуватися назовні.


5

Entity Framework виводить UoW & Repository (DbSet) з коробки

Ні.

Абстракції Entity Framework були створені з урахуванням ORM, а не DDD. DbSetАбстракції в будь-якої версії Entity Framework далеко не в простоті DDD Repository - не кажучи вже про DbContextякому виставляє мільйон річ більш UnitOfWork.

Ось невичерпний список елементів у рефераті EF Core 2.1, DbSet<TEntity>який нам не потрібен у DDD:

  • Attach(TEntity) і всіх її побратимів
  • Find(Object[])
  • Update(TEntity) і всіх її побратимів
  • Реалізація IQueryable

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

Підсумок: ви повинні перетворити ці смаколики на приємні, обтічні концепції та здогадатися, що це означає введення додаткових занять.

Порівняно надійний приклад того, що можна зробити з EF та DDD (хоча деякі висловлені точки зору є дискусійними): https://kalele.io/blog-posts/modeling-aggregates-with-ddd-and-entity-framework/

інші рішуче генерують додаткові шари, часто навіть порушуючи SRP, вводячи DbContext в агрегатні корені

Я дійсно не бачу зв’язку між двома частинами цього речення. Незалежно від підходу, у DDD є те, що називається Application Service, і саме там ви маніпулюєте Блоком роботи / сховищем (або DbContext). Не в сукупних коренях.

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


2

Конфлікти:

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

реалізуючи додатковий шар сховища, ми ігноруємо вбудовані функції EF (кожен DbSet вже є репо) і надмірно ускладнює додаток

Я використав підхід, коли кожен агрегат отримує свій власний DBContext, відображаючи лише те, що потрібно для агрегату. Я думаю, що це також описала Джулі Лерман.

Це вийшло дуже добре, але може не вистачити для більш цікавих моделей, де ви не хочете пов'язувати свої концепції з вашими сутностями.



Чи є якісь переваги підходу DBContext Per Aggregate? Це спосіб за замовчуванням реалізувати DDD за допомогою EF?
Алекс Герман

Чи не означала Джулі Лерман DbContext за обмежений контекст?
Mvision

0

Просто хотілося б поділитися можливим рішенням для розгляду:

  1. уникайте посилань на проект EF безпосередньо в службовому шарі

  2. створити додатковий шар репозиторію (використовує проект EF і повертає зведений корінь)

  3. посилання на рівень шару сховища в проектному шарі

Архітектура :

  • UI

  • Шар шару контролера

  • Службовий шар

  • Шар сховища

  • Entity Framework

  • Основний проект (містить моделі EF)


Підводні камені, які я бачу при такому підході:

  • якщо репозиторій повертає зведене коріння не як дерево моделей EF (наприклад, ми повертаємо відображений об’єкт) - ми втрачаємо здатність EF відстежувати зміни

  • якщо корінний корінь є моделлю EF - всі його навігаційні властивості все ще доступні , навіть якщо ми не можемо мати справу DbContext(ми не посилаємось на проект EF у службовому шарі)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.