Правильный шаблон для вставки или обновления существующего объекта с реактивными данными пружины - PullRequest
0 голосов
/ 23 февраля 2019

Я реализую приложение с пружинными данными (монго).

  • Получает данные из внешнего сервиса
  • Сохраняет их в БД
  • Если элемент не существуетЯ хотел бы вставить его в db
  • Если элемент существует, но имеет тот же хэш md5 с внешним элементом - ничего не делать
  • Если элемент существует в БД и хэши md5 не равны Мне бы хотелосьчтобы обновить его

У меня есть код

public Mono<Void> processItems() {  
  return externalService.getItems() //this returns Flux<Item>
         .flatMap(this::createOrUpdateItem)
         .flatMap(itemRepository::save)
         .then() 
}

private Mono<Item> createOrUpdateItem(Item item) {  
  return itemRepository.findById(item.getId) //this returns Mono<Item>
          .flatMap(itemFromDb -> updateItem(itemFromDb, item))
          .defaultIfEmpty(item) 
}

private Mono<Item> updateItem(Item itemFromDb, Item item){
  if(itemFromDb.getMd5.equals(item.getMd5)){
     return Mono.just(itemFromDb);
  }

  itemFromDb.setName(item.getName)
            .setDescription(item.getDescription); 

  return Mono.just(itemFromDb);
}

Как это работает:

  • Если элемент не существует, он сохраняется в БД
  • Если элемент существует и имеет тот же хеш md5, updateItem возвращает существующий в БД, а версия в БД увеличивается
  • Если элемент существует, и хэши md5 не равны, updateItem устанавливает поля и возвращает существующий в БД, а версия в БД увеличивается

Проблема в : когда хэш md5 равен, я не хочу вызывать DB.Потому что это увеличивает версию элемента в БД, но изменений не было.Как правильно реализовать этот алгоритм?

Я могу использовать @EqualsAndHashCode (exclude = "id"), но не уверен, что это правильный путь

1 Ответ

0 голосов
/ 24 февраля 2019

Единственный отсутствующий ингредиент в вашем примере - это продолжение пустого потока, если ничего не нужно делать.

Это решение на самом деле похоже на ваше, но имеет четкое разделение проблем.

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

public Mono<Void> processItems() {  
  return externalService.getItems() //this returns Flux<Item>
         .flatMap(this::loadExistingItem)
         .flatMap(this::setupOperation)
         .flatMap(this::saveItem)
         .then() 
}

private Mono<List<Item>> loadExistingItem(Item item) {  
  return itemRepository.findById(item.getId)
           .map(fromDb -> Arrays.asList(item, fromDb))
           .defaultIfEmpty(() -> Arrays.asList(item, null));
}

private Mono<Item> setupOperation(List<Item> items) {
  Item newItem = items.get(0);
  Item existingItem = items.get(1);

  if (existingItem == null) {
    return Mono.just(newItem);
  }

  if(newItem.getMd5().equals(existingItem.getMd5())){
    return Mono.empty();
  }

  existingItem.setName(newItem.getName)
  existingItem.setDescription(newItem.getDescription);

  return Mono.just(existingItem);
} 
...