如何在同一限界上下文中将查询数据库与命令数据库同步?

How to sync query database with command database in same bounded context?

我最近开始了一个使用 DDD 架构的新项目。对于相同的限界上下文,我有 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);
    }

}

但是我不知道是什么问题。一切运行没有一个错误,但我已经读取了保存到查询数据库中的模型并编写了模型 dosent。

如果我应该为读取模型使用单独的事务装饰器,我如何才能确定 运行 两个事务都正确无误?还是在发现错误时回滚?

或者命令完全错误,我不知道如何处理和同步读写!

我对 NH、EF 和事务管理知之甚少,所以这将是一个部分答案,试图解决您关于将事务用于写入和读取的问题。

  1. 通常,出于以下几个原因,您希望将查询模型构造机制与命令事务分开:

    一个。查询模型往往体积庞大

    b。根据需求构建的查询模型可能不止一种,通常由不同的 UI 屏幕或视图模型

  2. 决定
  3. 其次,为确保事务在查询模型持久性期间不会失败,您在命令模型事务中预先执行所有验证。查询模型构造应该是 activity 的基本 gather-and-serialize 类型,它以您想要的格式生成文档。它不应涉及验证。

  4. 使用相同的消息队列机制 运行 查询模型构建作为异步作业没有错。通常,查询模型是处理命令后生成的众多事物之一。一个好的机制是在命令处理结束时引发一个事件,并构造读取模型以响应该事件。

  5. 如果由于系统错误(磁盘已满、死锁等)导致查询模型构建失败,您可以依靠消息队列机制来跟踪和处理异常和失败事务。 (如果你还没有实现 retry/handle 消息处理失败的机制,你最好添加它)。

此机制假定您没有打包查询模型以响应应用层中的命令。如果你这样做,你应该避免它。假设并假设命令在处理后从不 return 任何数据。