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