我最近使用DDD Architecture开始了一个新项目。我有2个单独的数据库用于相同的有界上下文。我知道,不同的有界上下文通过消息队列互相交谈。但是由于我在相同的受限上下文中具有查询和命令功能,所以我不知道如何在相同的受限上下文中同步读取模型和写入模型。
我将NH用于写(命令)端,将EF用于读(查询)端。我将工作单元用于NH,并用工作单元修饰了我所有的命令,并使其按汇总进行事务处理:
public class NhUnitOfWork : IUnitOfWork
{
private readonly ISession _session;
public NhUnitOfWork(ISession session)
{
_session = session;
}
public void Begin()
{
_session.Transaction.Begin(IsolationLevel.ReadCommitted);
}
public void Commit()
{
_session.Transaction.Commit();
}
public void Rollback()
{
_session.Transaction.Rollback();
}
}
和事务装饰器:
public class TransactionalCommandHandlerDecorator<T>:ICommandHandler<T>
{
private ICommandHandler<T> _commandHandler;
private IUnitOfWork _unitOfWork;
public TransactionalCommandHandlerDecorator(ICommandHandler<T> commandHandler, IUnitOfWork unitOfWork)
{
_commandHandler = commandHandler;
_unitOfWork = unitOfWork;
}
public void Handle(T command)
{
_unitOfWork.Begin();
try
{
_commandHandler.Handle(command);
_unitOfWork.Commit();
}
catch (Exception exp)
{
_unitOfWork.Rollback();
throw;
}
}
}
因此,在应用程序层中,我必须在创建命令中协调业务流程:
public class CategoryCommandHandlers:ICommandHandler<CreateCategoryCommand>
{
private readonly ICategoryRepository _repository;
private readonly ICategoryQueryService _queryService;
public CategoryCommandHandlers(ICategoryRepository repository, ICategoryQueryService queryService)
{
_repository = repository;
_queryService = queryService;
}
public void Handle(CreateCategoryCommand command)
{
var categoryId = new CategoryId(Guid.NewGuid());
var parentId=new CategoryId(command.ParentId);
var category=new Category(categoryId,command.Name,parentId);
var parent = _repository.GetById(parentId);
if (parent==null)
throw new ParentCategoryNotFoundException();
_repository.Create(category);
var queryModel = new CategoryQuery(categoryId.Value, category.Name, parentId.Value);
_queryService.Create(queryModel);
}
}
但是我不知道这是什么问题。一切运行都没有一个错误,但我已将模型保存到Query数据库中并编写了模型主体。
如果我应该为读取模型使用单独的事务装饰器,如何确定正确运行两个事务而没有错误?还是回滚(如果发现错误)?
也许命令完全错误,并且我不知道如何处理和同步读取和写入!
答案 0 :(得分:0)
我对NH,EF和事务管理的了解还不够,所以这将是一个部分答案,试图解决您有关将单独的事务用于读写的问题。
通常,出于以下两个原因,您可能希望将查询模型的构建机制与命令事务分开:
a。查询模型往往很庞大
b。根据需求可能会构建多个查询模型,这些查询模型通常是由不同的UI屏幕或视图模型决定的
第二,要确保事务在查询模型持久化过程中不会失败,请在命令模型事务中预先进行所有验证。查询模型的构造应是基本的收集和序列化活动类型,该活动将以所需格式生成文档。它不应该涉及验证。
使用相同的消息排队机制将查询模型构造作为异步作业运行,这没有错。通常,查询模型是处理命令后生成的众多事物之一。一个很好的机制是在命令处理结束时引发一个Event并响应该事件构造读取模型。
如果由于系统错误(磁盘已满,死锁等)而导致查询模型构建失败,则可以依靠消息队列机制来跟踪和处理异常和失败的事务。 (如果您尚未实现重试/处理消息处理失败的机制,则最好添加它。)
此机制假定您没有打包响应于应用程序层中命令的查询模型。如果这样做,则应避免这样做。假设并执行命令,好像命令在处理后永不返回任何数据。