I've got a List<Order>
(or Flux<Order>
if I wanted) where each Order
element has a List<Item>
. I want to persist this object hierarchy into two tables of a relational database using spring-data-r2dbc
(and therefore ReactiveCrudRepository
) and spring-webflux
. These two tables have a foreign key constraint, so an Order
must be inserted before its Item
s.
Transaction handling is yet another topic and out of scope of this question. The return type of that part of the application should be a Flux<Order>
again, as it'll be the return value of a REST response.
The question is how to "combine" a Mono<Order>
and its Flux<Item>
.
I've looked into zipping but I couldn't get it to work (see commented out code below). Also I'm quite sure that zipping isn't the right thing anyway as I have one on one side and n on the other. I also tried .doOnSuccess
, but that also leaves the Flux<Item>
without a terminal operation.
SomeService.kt
fun saveOrders(orders: List<Order>): Flux<Order> {
// the flatMap (and flatMapMany below) with side effect isn't that nice either
return Flux.fromIterable(orders).flatMap { saveOrder(it) }
}
private fun saveOrder(order: Order): Mono<Order> {
val soonToBeSavedOrder: Mono<Order> = orderRepository.save(order)
val soonTeBeSavedItems: Flux<Item> = soonToBeSavedOrder.flatMapMany { saveItems(it) }
// TODO: how to "combine" the Mono and the Flux because the Flux doesn't
// have a terminal operation that way and therefore saveItems is never called.
return soonToBeSavedOrder
}
private fun saveItems(order: Order): Flux<Item> {
return itemRepository.saveAll(order.items)
}
Order.kt
class Order(
id: UUID,
var someData: String,
@Transient
val items: MutableList<Item> = ArrayList()) : Persistable<UUID> {
@Id
private var id: UUID = id
override fun getId(): UUID { return id }
override fun isNew(): Boolean { return true }
}
Item.kt
class Item(
id: UUID,
var someData: String) : Persistable<UUID> {
@Id
private var id: UUID = id
override fun getId(): UUID? { return id }
override fun isNew(): Boolean { return true }
}