在DDD的上下文中,当您处理域事件时,交易应从何处开始和结束?
Infrastructure.Layer具有UoW实施
/// => configured via DI as Per Request
class UnitOfWork : IUnitOfWork
{
ITransaction _transaction;
static ISessionFactory _factory;
ISession _session
UnitOfWork()
{
_session = _factory.OpenSession();
_transaction = _session.BeginTransaction(); ///=> start transaction
}
void Commit()
{
try
_transaction.Commit();
catch
_transaction.Rollback();
finally
Dispose();
}
}
Application.Layer UseCase处理程序
class SomeAppServiceUseCaseHandler : IUseCaseHandler
{
IUnitOfWork _uow;
ISomeRepo _repo;
AppService(IUnitOfWork uow, ISomeRepo repo)
{
_uow = uow;
_repo = repo;
}
void UseCaseHandler(Request request)
{
SomeAggregate agg = _repo.GetAggregate(request.Id)
agg.DoSomethingToChangeState();
_repo.UpdateAgg(agg);
_uow.Commit(agg); ///=> commit changes for this transaction success
}
}
,并且在Domain.Layer中具有该方法,该方法还将向域事件列表中添加用于聚合的Domain.Event。
SomeAggregate : AggregateRoot
{
DoSomethingToChangeState()
{
.... do something
var someObject;
base.AddEvent(new SomethingHappenedEvent(someObject)));
}
}
Application.Layer具有Domain.Event处理程序
class SomethingHappenedEventHander : Handler<SomethingHappenedEvent>
{
IRepo repo;
IUnitOfWork _uow;
DomainEventHander(IRepo repo, IUnitOfWork uow)
{
_repo = repo;
_uow= uow;
}
HandleEvent(someObject)
{
AnotherAggregate agg = new AnotherAggregate ();
agg.DoSomeCommand(someObject);
_repo.Create(agg);
_uow.Commit(); ///=> commit changes for same transaction fail, should rollback prev transaction as well
}
}
我觉得这不对
谁应该发布事件?从我看来,UoW应该在Commit()方法中这样做,但是我认为这是不对的,我认为UoW不应该这样做,但是我看不到还有谁可以。
如果在链中的某个点失败了,那么我已经提交了一些数据,如果一路失败了,我很可能不想这样做。
那么应该如何正确处理这两种情况?
答案 0 :(得分:1)
正如康斯坦丁所说,每个命令只能更新一个聚合。为什么?因为通过更新事务中的多个聚合,会降低系统的吞吐量。数据库事务边界越大,在写入数据时面临争用的可能性就越大,因此您希望保持事务的粒度尽可能细。
关于您的问题:
UnitOfWork当然可以保存更改。另外,您的Repo类也可以使用新方法IRepo.Save(Aggregate)进行相同操作:
_repo.Save(agg);
您的关注点是有效的。您可以(可能应该)将UnitOfWork移出Handler / UseCaseHandler级别的范围,这样您就不必具有在每个处理程序中提交UoW的样板代码。然后,您可以将两个聚合保存在一个数据库事务中。更好的方法是采用允许您从故障中恢复的体系结构。您可以:
如果以上任何步骤失败,那么处理将从那时开始,并确保已完成工作。使用这种方法,您的应用程序更具弹性,并且可以正确地应用事务边界。