Чистая архитектура - как решать транзакции базы данных?

В "чистой архитектуре" интеракторы (варианты использования) отвечают за определение бизнес-логики. Большинство примеров определяют варианты использования таким образом:

public MyUseCase() {

  public boolean execute(...) {
    int id = repository.insert(a)
    if(id > 0) {
      b.aId= id;
      repository.insert(b);
      ...
    }
  }
}

Интеракторы используют в основном простые CRUD-подобные операции или запросы к хранилищу. Приведенный выше пример является синхронным для случая простоты, но вы можете найти репозитории с таким же подходом, используя асинхронные решения, такие как обратные вызовы или rxjava.

Но как насчет неравенства варианта использования. Например, вы не можете быть на 100% уверены, что после вставки a это все еще будет там, когда вы вставите b, Что делать, если после вставки a вы получаете RepositoryException при вставке b,

Все репозитории, которые я видел до сих пор, не учитывают это, поэтому мой вопрос:

Каково решение вышеуказанной проблемы в чистой архитектуре?

1 ответ

Решение

Этот ответ может быть немного запоздалым, но я боролся с той же проблемой и пришел к выводу, что управление транзакциями, на самом деле, является частью варианта использования - например, "Если что-то пойдет не так с B, верните состояние A". Таким образом, это может и должно быть явно указано в вашем UseCase, возможно, с каким-то "DataManagerRepo", например так:

public MyUseCase() {

    public boolean execute(...) {
        dataManagerRepository.openTransaction()
        try {
            int id = repository.insert(a)
            if(id > 0) {
            b.aId= id;
            repository.insert(b);
            ...
        }
        catch (MyException exc) {
            dataManagerRepository.rollbackTransaction()
        }

        dataManagerRepository.commitTransaction()
    }
}

Имена могут отличаться, чтобы абстрагировать механизм целостности, но идея та же. Надеюсь, это кому-нибудь поможет.

Другие вопросы по тегам