Единица работы с несколькими источниками данных? - PullRequest
9 голосов
/ 02 сентября 2010

Вполне возможно (даже вероятно), что я просто не совсем понимаю концепцию «единицы работы». По сути, я рассматриваю это как нечто вроде широкой транзакции, используемой в объектно-ориентированной среде. Запустите единицу работы, взаимодействуйте с объектами, фиксируйте или откатывайтесь. Но как это соотносится с фактическими транзакциями в хранилищах данных за этими объектами?

В системе с одной БД и ORM (например, NHibernate) это просто. Транзакция может быть поддержана через ORM. Но как насчет системы, в которой модели пользовательских доменов скрывают множество разнородных источников данных? И не все эти источники данных являются реляционными базами данных? (Здесь много сделано в файловой системе.)

Прямо сейчас я застрял в мысли, что «вы просто не можете поддерживать транзакции между БД SQL2005, БД SQL2000, БД DB2 и файловой системой - все в одной и той же« атомарной »бизнес-операции». Так что на данный момент разработчики в команде (которые обычно работают независимо друг от друга) несут ответственность за ведение транзакций вручную в коде. Каждая БД может иметь правильные транзакции, но бизнес-операция в целом проверяется вручную и уравновешивается на каждом значимом этапе.

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

Есть ли у кого-нибудь какие-либо советы или примеры того, как лучше всего подходить к подобному домену, или как к нему обращались раньше? Фактический «домен» в этом случае все еще находится в зачаточном состоянии, развиваясь как прототип, чтобы однажды расширить и использовать / заменить большую экосистему разрозненных унаследованных приложений. Так что есть много места для перепроектирования и ре-факторинга.

Для справки: 10 000-футовый вид конструкции, к которой я сейчас стремлюсь, таков: большая коллекция небольших, насколько возможно, глупых клиентских приложений, вызывающих центральную службу на основе сообщений. Сервис является входом в «доменное ядро» и может рассматриваться как одно большое приложение в стиле MVC. В службу направляются запросы (во многом как «действия»), которые обрабатываются обработчиками (во многом как «контроллеры»). Все процедурное идет туда. Они взаимодействуют с моделями, которые содержат все бизнес-правила. Модели публикуют события, которые слушатели («сервисы» - эта часть все еще облачна в дизайне и может быть улучшена) выбирают и обрабатывают, взаимодействуя с хранилищами (база данных x, база данных y, файловая система, электронная почта, любой внешний ресурс). Все весело вводят зависимости соответственно.

Извините за все многословие :) Но если у кого-нибудь есть какой-либо совет, я бы хотел его услышать. Даже (особенно), если этот совет звучит так: «Ваш дизайн плохой, попробуйте вместо этого ...» Спасибо!

1 Ответ

10 голосов
/ 03 сентября 2010

Ранее я работал над системой, которая могла бы выполнить это, и это довольно просто. Поскольку ваш проект находится на ранней стадии, возможно, это может быть полезной для вас информацией. К сожалению, у меня больше нет доступа к коду, но я все еще могу описать, как он работает.

То, что я сделал, построил мои репозитории, используя универсальную реализацию шаблона репозитория. Базовый тип хранилища всегда будет ссылками служб и UoW. Для обсуждения мы будем называть его BaseRepository. Буква «T» будет ограничена реализациями IEntity, которые обозначают Доменный объект. Из BaseRepository я создал другой набор базовых классов для компоновки, таких как SqlBaseRepository, XmlBaseRepository и т. Д.

UoW заботится только о том, чтобы что-то относилось к типу BaseRepository, в котором будут существовать основные функции. Базовый CUD (CRUD) будет представлен, предоставляя эквиваленты для Creates, Updates и Deletes. Каждый из них будет создавать делегата и помещать его в очередь внутри UoW, также передавая информацию о типе транзакции и соответствующие данные, необходимые для его завершения. UoW начал бы вести список того, какие репозитории должны были быть вовлечены в транзакцию, но все равно было все равно, какой это тип. По сути, постановка в очередь здесь подобна зачислению в транзакцию.

BaseRepository определил абстрактный метод, называемый чем-то вроде .ApplyChange (). Как только .Commit () был вызван в UoW, он создал бы TransactionScope () и начал бы вызывать delagates в списке, передавая информацию обратно .ApplyChange (). Фактическая реализация .ApplyChange () существует в конкретной базе репозиториев, то есть в SqlRepositoryBase и т. Д., И также может быть переопределена реализацией.

Там, где это было сложно, по крайней мере, я откатился назад. Я имел дело только с одной базой данных, но иногда были внесены изменения на основе файлов. Я добавил метод .RevertChange () и начал отслеживать исходное состояние и измененные состояния, так что я мог в основном применить обратную дельту, чтобы вернуться туда, где я находился в стеке файлов.

Хотел бы я быть более конкретным в реализации, но прошло уже больше года с тех пор, как я видел код сейчас. Я могу вам сказать, что основа для исходного кода была взята из книги Тима МакКарти " .NET-управляемый домен с C #: проблема - разработка - решение ". Большая часть моей реализации репозитория была основана на его примерах, при этом большинство моих настроек касалось UoW и их реализации.

Надеюсь, это немного поможет! : -)

...