У меня есть база данных с 3 таблицами:
Таблица A, содержащая данные объектов A Таблица B, содержащая данные объектов B Таблица C, которая содержит данные объектов C
Объекты могутиметь 0 или 1 B объектов B объектов может иметь 0 или 1 объектов C (я знаю, они могут быть только в одной таблице, но это только для примера)
Я хочу сделать CSV-файл из всегобаза данных: каждая строка должна содержать ровно один объект A, необязательно свой объект B и, необязательно, свой объект C.
Для каждой таблицы существует асинхронное хранилище, которое возвращает CompletionStage.Поэтому, когда я выбираю объекты A из хранилища A, я получаю обратно CompletionStage<List<A>>
.Когда он завершается, я делаю Map для каждого объекта A, заполняю его данными A и вызываю repositoryB.getB(A.id)
, который возвращает CompletionStage<Optional<B>>
.Если значение B отсутствует, я добавляю новую строку в мой CSV-файл с данными внутри карты.Если B присутствует, я добавляю его значения на карту и вызываю repositoryC.getC(B.id)
, который возвращает CompletionStage<Optional<C>>
.Если C присутствует, я добавляю его значения на карту и добавляю новую строку в файл CSV, если нет, тогда я просто добавляю новую строку.
Создание CSV завершено, когда все CompletionStages завершены.Я пытался использовать CompletableFuture.allOf (), но так как в начале я не знаю, сколько будет CompletionStage, я не могу добавить их все в метод allOf, поэтому я думаю, что мне нужно каким-то образом динамически добавлять Completionstages.Возможно ли это?
В настоящее время у меня есть рабочее решение, но оно блокируется после каждой выборки B и C, поэтому я хочу сделать весь код неблокирующим.
Это моя попытка разблокирования, но она не работает должным образом, так как некоторые из фьючерсов B и C не добавлены в список фьючерсов, поэтому код не ожидает их завершения:
CompletableFuture<List<CompletableFuture>> genereteCSV = repositoryA.getAs().thenApplyAsync(listA-> {
List<CompletableFuture> futures = new ArrayList<>();
for (A a : listA) {
Map<String, String> values = new Map<>();
addAvaluesToMap(values, A);
CompletableFuture Bfuture = repositoryB.getB(A.id).thenAcceptAsync((optionalB -> {
if (optionalB.isPresent()) {
addValuesToMap(values, B);
CompletableFuture Cfuture = repositoryC.getC(B.id).thenAcceptAsync(optionalC-> {
if (optionalC.isPresent()) {
addAvaluesToMap(values, C);
}
addMapValuesToCSV(values);
});
futures.add(Cfuture);
} else {
addMapValuesToCSV(values);
}
}));
futures.add(Bfuture);
}
return futures;
});
geerateCSV.thenApplyAsync(futureList-> CompletableFuture.allOf(futureList.toArray(new CompletableFuture<?>[0])))
.thenAccept(dummy->{System.out.println("CsV generation done");});