I'm using Quarkus version 3.13.0 and also using Hibernate Reactive.
I have created the code below using Mutiny's Uni.combine() to query two entities and then persist a third entity (Join Table) using both results.
I was bitten by this Hibernate limitation that prevents us to use the same session in parallel executions.
I'm new to Mutiny, so I would like a help to turn this code into a synchronous chain that would fix the error I'm getting, because I couldn't find any other method other than combine() that provides a BiFunction.
@POST
@Path("{userId}/teams/{businessUnitId}")
public Uni<RestResponse<UserDto>> assignToTeam(Long userId, Long businessUnitId, @RestQuery String pRole) {
if (businessUnitId == null || userId == null) {
throw new WebApplicationException(MSG_INVALID_PAYLOAD, 422);
}
return Uni.combine()
.all()
.unis(Panache.withTransaction(() -> userRepo.findById(userId)
.onItem()
.ifNull()
.failWith(new WebApplicationException(MSG_RESOURCE_NOT_FOUND, NOT_FOUND))),
Panache.withTransaction(() -> businessUnitRepo.findById(businessUnitId)
.onItem()
.ifNull()
.failWith(new WebApplicationException(MSG_RESOURCE_NOT_FOUND, NOT_FOUND))))
.with((user, bunit) -> {
BusinessUnitsUsers buu = new BusinessUnitsUsersBuilder().parentEntity(bunit)
.childEntity(user)
.role(pRole)
.build();
return user.assingToTeam(buu);
})
.chain(r -> Panache.withTransaction(() -> userRepo.persist(r))
.map(user -> RestResponse.ok(userMapper.toDto(user, usersBusinessUnitContext))));
}
This is the error I get:
2024-08-06 13:20:30,632 ERROR [http-problem] (vert.x-eventloop-thread-1) status=500, title="Internal Server Error": io.smallrye.mutiny.CompositeException: Multiple exceptions caught:
[Exception 0] java.lang.IllegalStateException: Session/EntityManager is closed
[Exception 1] io.vertx.core.impl.NoStackTraceThrowable: Transaction already complete
at io.smallrye.mutiny.groups.UniOnFailure.lambda$call$3(UniOnFailure.java:108)
This should work:
@POST
@Path("{userId}/teams/{businessUnitId}")
public Uni<RestResponse<UserDto>> assignToTeam(Long userId, Long businessUnitId, @RestQuery String pRole) {
if (businessUnitId == null || userId == null) {
throw new WebApplicationException(MSG_INVALID_PAYLOAD, 422);
}
return Panache
.withTransaction(() -> userRepo
.findById(userId)
.onItem().ifNull().failWith(new WebApplicationException(MSG_RESOURCE_NOT_FOUND, NOT_FOUND))
)
.chain( user -> Panache
.withTransaction(() -> businessUnitRepo
.findById(businessUnitId)
.onItem().ifNull().failWith(new WebApplicationException(MSG_RESOURCE_NOT_FOUND, NOT_FOUND))
)
.chain( bunit -> {
BusinessUnitsUsers buu = new BusinessUnitsUsersBuilder()
.parentEntity(bunit)
.childEntity(user)
.role(pRole)
.build();
return user.assingToTeam(buu);
} )
.chain(r -> Panache
.withTransaction(() -> userRepo.persist(r) )
.map(user -> RestResponse.ok(userMapper.toDto(user, usersBusinessUnitContext)))
);
)
}