I am looking into something similar and have come to the same conclusion (1), since there is no support for relations in R2DBC.
To migrate a one-to-many relation I first made the collection containing the "many" entities to @Transient in the "one" entity.
Persisting the "one" entity is accomplished using the following steps in a reactive sequence:
- Persist the "many" entities. This in order to be able to update these in the "one" entity so that the "many" entities are assigned ids.
- Persist the "one" entity.
- Persist the relationships. I can do this at this stage since I now have the ids of all involved entities. For the relationships I have introduced a helper entity, something along the lines of OneManyRelation and a corresponding repository.
In code it looks like this:
public <S extends Drawing> Mono<S> save(final S inDrawing) {
final List<Shape> theDrawingShapes = inDrawing.getShapes();
return Mono.defer(() -> {
return Flux.fromIterable(theDrawingShapes)
.log()
.flatMap(theDrawingShape -> {
/* Save the shapes contained in the drawing. */
if (theDrawingShape instanceof Circle) {
final Circle theUnsavedCircle = (Circle) theDrawingShape;
return mCircleRepository.save(theUnsavedCircle);
} else if (theDrawingShape instanceof Rectangle) {
final Rectangle theUnsavedRectangle = (Rectangle) theDrawingShape;
return mRectangleRepository.save(theUnsavedRectangle);
} else {
LOGGER.warn("Unrecognized entity type: {}",
theDrawingShape.getClass().getName());
return Mono.just(theDrawingShape);
}
})
/* Update the drawing, setting the shapes of the drawing to the saved shapes. */
.collectList()
.map(theSavedShapesList -> {
inDrawing.setShapes(new ArrayList<>(theSavedShapesList));
return inDrawing;
})
/* Save the drawing itself. */
.flatMap(theDrawing -> super.save(theDrawing))
.flatMap(theDrawing -> {
/* Save the relations between the drawing and the shapes of the drawing. */
return Flux.fromIterable(theDrawing.getShapes())
.flatMap(theDrawingShape -> {
final var theDrawingShapeRelation = new DrawingShapesRelation();
theDrawingShapeRelation.setDrawingId(theDrawing.getId());
theDrawingShapeRelation.setShapeId(theDrawingShape.getId());
theDrawingShapeRelation.setShapeType(theDrawingShape.getClass()
.getName());
return mDrawingShapesRelationRepository.save(theDrawingShapeRelation);
})
.collectList()
.map(theDrawingShapesRelationList -> theDrawing);
});
});
}
My conclusion this far is that unless you are certain that there are major gains to be made from switching to R2DBC, I would settle for using Spring Data JPA and executing calls to repositories in a separate thread using subscribeOn.
Good luck and happy coding!