Немного размышлений о домене и инфре
Предположим вам надо написать десктопное приложение, где будет свое состояние с набором коллекций и других свойств. Объекты для отображения могут храниться древовидно, содержать различные свойства со своей логикой и.т.д.
Для быстрой реализации этого, надо, как минимум, создать 3 проекта: проект с формочками, проект с доменное логикой, там где будут манипуляции с объектами: вставкой, удалением и.т.д. И проест с инфраструктурой: работой с бд, файловой системой и.т.д.
Зависимости проектов будут такими: проекты с формочками и инфрой с бд будут зависеть от проекта с доменными моделями, там где основное поведение и бизнес логика приложения.
Формочки используют интерфейсы с методами из доменного проекта, а инфра реализует доменные интерфейса для доступа к данным, работе с фалами и другие взаимодействия, которые не важны в бизнес логике.
Итого так реализуется основное ядро чистой архитектуры. Но что дальше?
Дальше встает вопрос можно ли использовать доменные объекты в представлении? Много кто считает нет. У этого есть свои обоснования, например, различные «свои» привязки к представлению, такие как атрибуты.
Но в некоторых случаях, если логика допускает, можно использовать и их не испытывая никаких лишений. Повторюсь: в некоторых. В любом случае можно всегда создать еще один набор типов для представления, как это всегда делается в web api.
Теперь перейдем к рассмотрению различных кейсов приложения: управление доменными объектами.
Предположим приложение может создавать список, добавлять в список другой список, менять порядок, изменять объект, удалять, вставлять, копировать и.т.д.
Для каждого действия надо написать логику в доменном проекте и реализовать ее сохранение, например на ef core сущностях.
При написании таких методов можно заметить, что доменные и методы для работе с ef core местами дублируют логику, но местами имеют очевидные различия. Вставка в коллекцию и выполнение проверок, присваивание свойств и.т.д.
Вот было бы классно изменять только доменные модели? И не поддерживать два мира с похожим поведение, но разной сутью.
Я как то сталкивался с таким совмещением, где ef core модель приколачивается в доменной и живет с ним. С таким подходом есть минусы: зависимость от инфры, либо дополнительная куча абстракций. И сохранение ef core сущности долгое время. Вместо этого поддержка целых «дублирующих» методов для сохранения в бд выглядит на мой взгляд лучше…
При сохранении надо открыть транзакцию, быстро применить изменения и закрыть транзакцию. При прибивании сущности бд к доменному объекту это так же будет обеспечено. Однако нет гарантии что они будут всегда иметь высокое соответствие, должна быть гибкость.
Устав плодить и искать несоответствия у двух параллельных миров я наконец-то решился сделать трекер для доменных обетов. О таком я читал в нескольких книгах, и это вполне нормальный uof.
Что надо трекать? Это свойства и коллекции. Как надо трекать? Завести коллекцию с командами. Звучит сложно, но на современном c# это оказалось очень просто и без рефлексий и всяких подписок.
При изменении свойств добавляем в список делегат, который меняет сущность ef core. При изменении коллекций вычисляем новые элементы и кладем соответствующие делегаты в список изменений. Однако при удалении объекта лучше вызвать трекающий метод отдельно, ну либо подумать как впихнуть это в домен. Возможно надо подсчитать ссылающихся на объект и удалить если таких уже нет. Однако у меня есть корневые объекты и такое не подходит.
Итого после доменных изменений надо вызвать один метод трекера, который по сути uof. В нем создается скоуп зависимостей, и затем выполняются действия на сущностях. Если сущности нет в результате вызова Find (id), то ее можно создать без особых отдельных делегатов создания через Set
В данный момент у меня есть работающая простая реализация, которая, вероятно, будет меняться и пока я её не выложу. Но уже разработка стала гораздо легче.