Как синхронизировать базу данных запросов с базой команд в том же ограниченном контексте? - PullRequest
0 голосов
/ 09 июня 2019

Я недавно начал новый проект с использованием архитектуры DDD. У меня есть 2 отдельные базы данных для одного и того же ограниченного контекста. Я знаю, что разные ограниченные контексты общаются друг с другом через очереди сообщений. Но поскольку у меня есть функции запросов и команд в одном и том же ограниченном контексте, я не знаю, как синхронизировать и модель чтения, и модель записи (в одном и том же ограниченном контексте).

Я использовал NH для записи (Command) и EF для чтения (Query). Я использовал Unit Of Work для NH, украсил все свои команды Unit Of Work и сделал их транзакционными для агрегата:

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, и записал модель, отправленную.

Если у меня должен быть отдельный транзакционный декоратор для модели чтения, как я могу быть уверен в правильном выполнении обеих транзакций без ошибок? или откат, если кто-то обнаружил ошибку?

Или, может быть, команда совершенно неверна, и я не знаю, как обрабатывать и синхронизировать чтение и запись!

1 Ответ

0 голосов
/ 09 июня 2019

Я не знаю достаточно о NH, EF и управлении транзакциями, поэтому это будет частичный ответ, попытка ответить на ваш вопрос о наличии отдельных транзакций для записи и чтения.

  1. Как правило, вы хотите отделить механизм построения модели запроса от командной транзакции по нескольким причинам:

    а. Модели запросов имеют тенденцию быть громоздкими

    б. Может быть несколько моделей запросов, построенных на основе требований, часто продиктованных различными экранами пользовательского интерфейса или моделями представления

  2. Во-вторых, чтобы гарантировать, что транзакция не завершится с ошибкой во время сохранения модели запроса, вы выполняете всю предварительную проверку внутри транзакции модели команды. Построение модели запроса должно быть элементарным видом деятельности «собирать и сериализовать», который создает документ в нужном вам формате. Он не должен включать проверки.

  3. Нет ничего плохого в использовании того же механизма очереди сообщений для запуска построения модели запроса в качестве асинхронного задания. Зачастую модели запросов являются одной из многих вещей, генерируемых после обработки команды. Хороший механизм - вызвать событие в конце обработки команды и построить модель чтения в ответ на событие.

  4. Если построение модели запроса завершается неудачей из-за системной ошибки (переполнение диска, взаимоблокировка и т. Д.), Вы можете зависеть от механизмов очередей сообщений для отслеживания и обработки исключений и неудачных транзакций. (Если вы не внедрили механизм для повторения / обработки ошибок обработки сообщений, желательно добавить его).

Этот механизм предполагает, что вы не упаковываете модель запроса в ответ на команду на прикладном уровне. Если вы делаете это, вам следует избегать этого. Предположим, что команды никогда не возвращают никаких данных после обработки.

...