Как кодировать в реакторе, чтобы обновить определенное поле в записи БД cassandra - PullRequest
0 голосов
/ 29 июня 2018

Я использую ReactiveCassandraRepository и могу создать новую запись, как показано ниже.

public Mono<String> saveAbc(Abc toBeSaved) {
    return abcRepository.save(toBeSaved).map(saved -> saved.getId());
}

Но я не мог себе представить, как обновить определенное поле в записи БД, поскольку в нем задействованы 2 реактивные операции (findById & save).

Я написал следующий код для создания или обновления статуса, если он существует, но, похоже, он не работает.

public Mono<String> saveAbc(Abc toBeSaved) {
    return abcRepository.findById(toBeSaved.getId())
        .map(current -> abcRepository.save(transform(toBeSaved, current)).map(saved -> saved.getId()))
        .flatMap(id -> id);
}

private Abc transform(Abc toBeSaved, Abc current) {
    if(current == null) {
        return toBeSaved;
    } else {
        current.setStatus(toBeSaved.getStatus());
        return current;
    }
}

Может кто-нибудь помочь с этим?

1 Ответ

0 голосов
/ 03 июля 2018

Я ожидаю, что метод вашего abcRepository будет выглядеть примерно так:

interface AbcRepository {
    Mono<Abc> findById(String id);

    Mono<Abc> save(Abc abc);
}

Я думаю, из вашего кода, для данного Abc вы хотите

  1. читать Abc из хранилища с тем же идентификатором,
  2. сопоставить данные из данного Abc с найденным,
  3. или просто используйте данный Abc, если хранилище не нашло,
  4. асинхронно сохраните этот Abc
  5. и вернуть идентификатор сохраненного элемента как Mono

Я бы сделал это так:

public Mono<String> saveAbc(Abc toBeSaved) {
    return abcRepository.findById(toBeSaved.getId()) // (1)
            .map(abc -> transform(toBeSaved, abc))   // (2)
            .defaultIfEmpty(toBeSaved)               // (3)
            .flatMap(abcRepository::save)            // (4)
            .map(Abc::getId);                        // (5)
}

private Abc transform(Abc toBeSaved, Abc current) {
        current.setStatus(toBeSaved.getStatus());
        return current;
}

Mono может принимать только один элемент или не иметь его, поэтому при использовании Mono: map (2) вам не нужно обрабатывать нулевые значения. Mono, возвращаемый abcRepository, получит найденный Abc, в этом случае вызов преобразования (2) будет выполнен, или он просто выдаст полный сигнал, и в этом случае карта ничего не делает, а defaultIfEmpty (3) отправляет toBeSaved как запасной вариант.

Если у вас есть преобразование, которое само по себе асинхронно и, следовательно, приводит к тому, что другой Mono использует flatMap (4), иначе ваш промежуточный результат будет Mono<Mono<Abc>>.

И всегда помните: ничего не происходит, пока не будет вызвана подписка.

saveAbc(myNewAbc).subscribe(id -> System.out.println("Saved Abc with id: " + id));

В приведенном выше примере я ожидал, что ваш репозиторий просто выдаст полный сигнал, когда findById не найдет подходящий Abc, который завершит Mono как пустой (что имеет место при использовании ReactiveCassandraRepository !). Если вместо этого хранилище выдает исключение, в этом случае вы можете, например, использовать

.onErrorResume(t -> Mono.just(toBeSaved))

вместо defaultIfEmpty (3).

...