Чистая архитектура - как решать транзакции базы данных?
В "чистой архитектуре" интеракторы (варианты использования) отвечают за определение бизнес-логики. Большинство примеров определяют варианты использования таким образом:
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()
}
}
Имена могут отличаться, чтобы абстрагировать механизм целостности, но идея та же. Надеюсь, это кому-нибудь поможет.