UoW на больше , чем просто транзакция. Ниже приводится цитата Мартина Фаулера :
Единица работы отслеживает все, что вы делаете во время бизнес-транзакции, которая может повлиять на базу данных. Когда вы закончите, он выяснит все, что нужно сделать, чтобы изменить базу данных в результате вашей работы.
Стоит:
- Укажите контекст для ваших репозиториев
Либо разрешите создавать хранилища из этого экземпляра UoW, либо разрешите внедрить этот экземпляр UoW в хранилище. Я предпочитаю первый подход. Все репозитории с конструктором internal
и некоторыми фабричными методами в UoW создают репозитории.
- Отслеживать изменения в этом контексте
Это сложная тема, но для простоты ограничимся транзакцией базы данных. Многие ОРМ справляются с этим лучше. Отслеживание состояния объектов Entity может быть выполнено несколькими способами. Вести список изменений, поддерживать состояние (грязное или нет) объекта или сохранять исходную копию объекта и сравнивать его с окончательной копией в конце и т. Д.
- Flush / Don't-Flush изменения, сделанные в этом контексте
Это связано с вышеуказанным пунктом. На основе отслеживания решите, какие изменения необходимо перенести в хранилище. Некоторые реализации UoW также поддерживают автоматическую очистку, когда UoW автоматически решает , когда , чтобы сбросить изменения. Изменения сбрасываются, если все было в порядке; не покраснел, если была проблема. Опять же, давайте для простоты ограничим это транзакцией базы данных. Для подробных реализаций лучше использовать ORM.
- Создание и очистка ресурсов
Экземпляр UoW должен создавать (автоматически или вручную) ресурсы, необходимые для выполнения действий, и очищать их, когда они больше не нужны.
interface IUnitOfWork : IDisposable
{
IDbConnection Connection { get; }
IDbTransaction Transaction { get; }
void Begin();
void Commit();
void Rollback();
IRepository CreateRepository(....);
}
Метод CreateRepository
создает экземпляр хранилища под этим UoW. Таким образом, вы можете использовать один и тот же UoW в нескольких репозиториях. Таким образом, одна транзакция БД может быть распределена по нескольким репозиториям. Другой альтернативой является внедрение UoW в хранилище, как показано здесь .
Проблема с этим подходом состоит в том, что он не заставляет UoW. Вызывающая сторона может (или должна) начать транзакцию.
Другая мини-версия UoW (которая заставляет UoW), которую я могу себе представить, выглядит примерно так:
public sealed class UoWSession
{
public UoWSession()
{
//Open connection here
//Begin transaction here
}
IRepository CreateRepository(....)
{
//Create and return the requested repository instance here
}
void Commit()
{
transaction.Commit();
}
void Dispose()
{
//If transaction is not commited, rollback it here.
//Cleanup resources here.
}
}
Без использования ORM вы должны выставить что-то , которое говорит вам, что все было хорошо. Выше реализация использует Commit
метод.
Может быть простое свойство, скажем, IsAllWell
, которое по умолчанию равно false
, и вызывающий код устанавливает его явно. Затем ваш метод Dispose
фиксирует или откатывает транзакцию на основе свойства. В этом случае вам не нужно показывать метод Commit
, поскольку вы обрабатываете его внутри флага.