Подводные камни доменного дизайна с Entity Framework

12

Многие учебники по DDD, которые я изучал, в основном охватывают теорию. Все они имеют примеры элементарного кода (Pluralsight и аналогичные).

В Интернете также предпринимаются попытки нескольких людей создать учебники по DDD с EF. Если вы начнете их изучать ненадолго - вы быстро заметите, что они сильно отличаются друг от друга. Некоторые люди рекомендуют держать приложение минимальным и избегать введения дополнительных слоев, например, хранилища поверх EF , другие решительно генерируют дополнительные слои, часто даже нарушая SRP, внедряя DbContextв Aggregate Roots.

Я ужасно извиняюсь, если задаю основанный на мнении вопрос, но ...

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


Важные аспекты:

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

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

  • с EF все модели всегда доступны выключены DbContext(они представлены как DbSet)

Ловушки:

  • Вы не можете гарантировать, что ваши дочерние модели будут затронуты только через Aggregate Root - ваши модели имеют свойства навигации, и их можно изменить и вызватьdbContext.SaveChanges()

  • с помощью которого DbContextвы можете получить доступ к каждой модели, таким образом обойдя Aggregate Root

  • вы можете ограничить доступ к дочерним элементам корневого объекта с помощью метода ModelBuilderin , пометив их как поля - я до сих пор не верю, что это правильный путь для DDD, плюс трудно оценить, к каким приключениям это может привести в будущем ( довольно скептически )OnModelCreating

конфликты:

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

  • реализуя дополнительный уровень хранилища, мы игнорируем встроенные функции EF (каждый DbSetуже является репо) и усложняем приложение


Мой вывод:

Прошу прощения за мое невежество, но на основании приведенной выше информации - либо Entity Framework не подходит для доменно-управляемого дизайна, либо доменно-управляемый дизайн является несовершенным и устаревшим подходом.

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


Если я не прав - может кто-нибудь хотя бы подробно описать простой набор инструкций (или даже предоставить приличные примеры кода), как работать с DDD с EF, пожалуйста?

Алекс Герман
источник
Я подробно описал здесь шаги в соответствии с моим пониманием того, как работает EF. Тем не менее, эти шаги не решают проблему доступа к детям с помощью nav. свойства или DbSets от DbContext.
Алекс Герман

Ответы:

8

DDD и EF имеют мало общего между собой.

DDD - это концепция моделирования. Это означает думать о Домене, Бизнес-требованиях и моделировать их. Особенно в контексте объектной ориентации это означает создание дизайна, который отражает бизнес-функции и возможности.

EF - это технология постоянства. В основном это касается данных и записей базы данных.

Эти двое резко разведены. Конструкция DDD может использовать EF в некоторой форме под капотом, но эти два не должны взаимодействовать любым другим способом.

Некоторые интерпретации доменного дизайна на самом деле поддерживают моделирование данных, и я думаю, что это ваш вопрос. В этой интерпретации «сущности» и «объекты значений» по сути являются только бессистемными держателями данных, и проект касается самих себя, какими свойствами они обладают и как они связаны между собой. В этом контексте DDD против EF может подойти.

Эта интерпретация, однако, ошибочна, и я настоятельно рекомендую полностью ее игнорировать.

В заключение : DDD и EF не являются взаимоисключающими, они фактически не имеют отношения друг к другу, если вы выполняете правильное моделирование объектов, а не моделирование данных. Объекты DDD не должны быть в той или иной форме артефактами EF. Например, объекты DDD не должны быть EF-объектами. Внутри какой-либо бизнес-функции в проекте 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 есть вещь, называемая Службой приложений, и именно здесь вы манипулируете Единицей Работы / Хранилищем (или DbContext). Не в общих корнях.

В то время как это могло бы быть правильным подходом, если бы это был образованный компромисс, недавняя антирепозитивная тенденция «минимализм Entity Framework» является бредовой. Он обвиняет шаблоны DDD в трении, которое происходит с Entity Framework, когда действительно создатели EF ничего не сделали для того, чтобы сделать их среду совместимой с лучшими практиками из коробки. Все это время они тесно связаны с этой самой средой со всеми проблемами с точки зрения безопасности кода и возможности сопровождения, которые могут возникнуть.

guillaume31
источник
2

конфликты:

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

реализуя дополнительный уровень хранилища, мы игнорируем встроенные функции EF (каждый DbSet уже является репо) и усложняем приложение

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

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

MVG
источник
Посмотрел
Алекс Герман
Есть ли какие-либо преимущества подхода DBContext Per Aggregate? Это стандартный способ реализации DDD с EF?
Алекс Герман
Разве Джули Лерман не имела в виду DbContext в ограниченном контексте?
Mvision
0

Просто хотел бы поделиться возможным решением для рассмотрения:

  1. избегать прямой ссылки на проект EF в Service Layer

  2. создайте дополнительный слой репозитория (использует проект EF и возвращает Aggregate Root)

  3. ссылка на слой репозитория в проекте уровня сервиса

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

  • UI

  • Уровень контроллера

  • Сервисный уровень

  • Слой репозитория

  • Entity Framework

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


Подводные камни, которые я вижу при таком подходе:

  • если репозиторий возвращает Aggregate Root не как дерево модели EF (например, мы возвращаем отображенный объект) - мы теряем способность EF отслеживать изменения

  • если Aggregate Root является моделью EF - все его навигационные свойства все еще доступны , хотя мы не можем иметь с ними дело DbContext(мы не ссылаемся на проект EF в Service Layer)

Алекс Герман
источник