Зачем мне использовать шаблон Unit of Work поверх сеанса NHibernate?
-
13-09-2019 - |
Вопрос
Когда бы мне написать реализацию UoW поверх того, что уже предоставлено NHibernate?Есть какие-нибудь примеры из реального мира?
Решение
Единица работы, которую вы описываете, уже предоставлена NHibernate, поэтому нет причин выполнять такую единицу работы.
То, что мы имеем в нашем сервисе WCF, - это единица измерения более высокого уровня, которая содержит информацию, важную в нашем приложении для текущей единицы измерения.Это включает в себя абстрагирование NHibernate ISession для нас.Когда вы разбиваете его на части, у вас получается код, который можно разделить на три категории
Код, который должен иметь дело с Единицей работы.Не имеет значения, кто поддерживает единицу работы.Это может быть NHibernate, iBatis или пользовательский ORM.Все, что нужно сделать коду, это Загрузить, откатить, Сохранить и т.д.Он не заботится и не должен заботиться о механизме, используемом для этого.
Код, который должен иметь дело с ISession напрямую, потому что он выполняет специфические для NHibernate действия.Обычно это связано со сложными запросами, которые необходимо создать.
Не нужно знать, что он выполняется в Единице работы, или обращаться к ISession.Мы можем полностью проигнорировать это как часть данного обсуждения.
В то время как код в 1.может просто работать против ISession мы предпочитаем пытаться абстрагироваться от вещей в коде, которые мы напрямую не контролируем или которые могут измениться.Это имеет ценность по двум причинам.
Когда мы начинали, мы не были на 100% проданы на NHibernate.Мы рассматривали iBatis или что-то нестандартное.Очевидно, что это больше не проблема.
Вся команда не является экспертами в NHibernate, и мы не хотим, чтобы они ими были.По большей части люди пишут код, который подпадает под категорию 1.и все, о чем они знают, - это о нашем Подразделении.Когда код относится к категории 2.это должно быть написано людьми в команде, которые хорошо понимают NHibernate.
Итак, в заключение я бы сказал, что тип единицы измерения, о котором вы говорите, не нужен, я бы предположил, что единица измерения более высокого уровня может обеспечить большую ценность.
Другие советы
Мой базовый рабочий интерфейс содержит следующие методы - Инициализировать - Зафиксировать - Откат - IDisposable.Утилизировать
Я использую его как для управления сеансами, так и для управления транзакциями.Это полезно, потому что мне не нужно писать этот код снова и снова для разных областей сеанса.(единица работы на запрос, на серию запросов, на поток и т.д.)
При условии, что вы правильно настроили все свои сопоставления (т.е.каскады), вам не нужно делать ничего особенного и ISession
сойдет просто отлично.Однако, если вы пишете трехуровневое приложение, вам придется вручную упорядочивать операции с базой данных, которые вы хотите выполнить в рамках одной транзакции."Эталонная реализация" Фаулера в "Шаблонах архитектуры корпоративных приложений" может стать хорошей отправной точкой:
class UnitOfWork...
public void registerNew(DomainObject obj) {
Assert.notNull("id not null", obj.getId());
Assert.isTrue("object not dirty", !dirtyObjects.contains(obj));
Assert.isTrue("object not removed", !removedObjects.contains(obj));
Assert.isTrue("object not already registered new", !newObjects.contains(obj));
newObjects.add(obj);
}
public void registerDirty(DomainObject obj) {
Assert.notNull("id not null", obj.getId());
Assert.isTrue("object not removed", !removedObjects.contains(obj));
if (!dirtyObjects.contains(obj) && !newObjects.contains(obj)) {
dirtyObjects.add(obj);
}
}
public void registerRemoved(DomainObject obj) {
Assert.notNull("id not null", obj.getId());
if (newObjects.remove(obj)) return;
dirtyObjects.remove(obj);
if (!removedObjects.contains(obj)) {
removedObjects.add(obj);
}
}
public void registerClean(DomainObject obj) {
Assert.notNull("id not null", obj.getId());
}