Смысл Dispose
в том, что он всегда запущен.И используя эту идиому коммита отката, вам не нужно знать разницу.
using (var unitOfWork = new UnitOfWork())
{
// use unitOfWork here - No need to worry about transactions for this code.
unitOfWork.Commit();
}
Здесь мы видим, что либо выдается исключение, либо unitOfWork фиксируется.Затем мы можем иметь логическое значение в UnitOfWork
, отслеживающее, был ли выполнен коммит или нет.Тогда Dispose
откат может не зафиксирован.Таким образом, единица работы всегда либо откатывается, либо фиксируется.
Я бы в любом случае избегал фиксации внутри Dispose.Для начала метод ITransaction.Commit
обычно может выдавать исключения из-за ошибок - это совершенно нормально.Однако метод Dispose
- это , который не должен выдавать исключений.Смотрите эту ссылку и ищите в Stackoverflow для получения более подробной информации о почему .
Я думаю, что-то вроде этого крупными штрихами
class UnitOfWork : IDisposable
{
ISession _session;
ITransation _transaction;
bool _commitTried;
// stuff goes here
void Commit()
{
_commitTried = true;
_transaction.Commit();
}
void Dispose()
{
if (!_commitTried) _transaction.Rollback();
_transaction.Dispose();
_session.Dispose();
}
}
Проблема с полным забыванием вызова Commit, я бы сказал, не так велика, поскольку, если не зафиксировано, код клиента не будет работать , так как транзакция Rollback
'ed и изменения не применяются, которые будут обнаружены.при выполнении кода внутри прибора или вручную.
На самом деле я пытался справиться с этим в одном проекте, используя синтаксис с лямбдами, например:
_repository.InTransactionDo(ThisMethodIsRunInsideATransaction);
Таким образом, клиентам не нужно былобеспокоиться о совершении чего-либо.Я на самом деле в итоге пожалел об этом, потому что это слишком усложняло вещи, и пожалел, что ушел с вышеуказанным подходом.