Quarkus: как изменить метод с императивного на реактивный
Я создаю небольшой Rest API, чтобы больше узнать о фреймворке Quarkus. Теперь я хотел бы начать использовать фреймворк с его реактивным API, но мне сложно понять некоторые концепции. В настоящее время проект использует RESTEasy Reactive с Jackson, Hibernate Reactive с Panache и Postgresql Reactive Client.
Это мои занятия
@Table(name = "cat_role")
@Entity
public class Role extends PanacheEntityBase {
private static final long serialVersionUID = -2246110460374253942L;
@Id
@Column(name = "id", nullable = false, updatable = false)
@GeneratedValue
public UUID id;
@Enumerated(EnumType.STRING)
@Column(name = "name", nullable = false, length = 18)
public UserRole name;
public enum UserRole {
Administrador, Asesor_Empresarial, Asesor_Academico, Alumno
}
}
Сейчас в моем сервисе (обязательно) делаю следующее:
Role.class
public static Boolean existsRoleSeed(){
return Role.count() > 0;
}
RoleService.class
@Transactional
public void seedRoles() {
if (!Role.existsRoleSeed()) {
for(Role.UserRole userRole: Role.UserRole.values()){
Role role = Role.builder()
.name(userRole)
.build();
role.persist();
}
}
}
Это, очевидно, зарегистрирует все роли из перечисления UserRole в базе данных, и оно будет работать правильно. Я пытаюсь воспроизвести этот метод, но с использованием реактивной формы. Это изменения, которые я внес в код
Role.class
public static Uni<Boolean> existsRoleSeed() {
return Role.count().map(x -> x > 0);
}
RoleService.class
@ReactiveTransactional
public void seedRoles() {
Role.existsRoleSeed()
.map(exists -> {
if (!exists) {
Multi.createFrom()
.iterable(Arrays
.stream(Role.UserRole.values())
.map(userRole -> Role.builder()
.name(userRole)
.build())
.collect(Collectors.toList()))
.map(role -> role.persistAndFlush())
.subscribe().with(item -> LOGGER.info("Something happened"), failure -> LOGGER.info("Something bad happened"));
}
return null;
}).subscribe().with(o -> {
});
}
Когда я запускаю приложение, оно не выдает ошибок, журналы показывают, что что-то произошло, база данных создает таблицу, но ничего не вставляет. Я пробовал по-разному, но заставить работать так, как я надеюсь, не получилось.
2 ответа
Основываясь на ответе @Haroon и комментарии @Clement, я сделал следующее
- Удален @ReactiveTransactional, поскольку мой метод возвращает void и не находится на границе REST
- Когда я удалил аннотацию, мне нужно использовать метод Panache.withTransaction
- И, наконец, в методе я подписался на мульти
Одно замечание: я изменил transformToUniAndMerge с ответа @Haroon на transformToUniAndConcatenate, чтобы сохранить порядок ролей.
public void seedRoles() {
Role.existsRoleSeed()
.onItem().transformToMulti(exists -> {
if (!exists) {
return Multi.createFrom().items(Role.UserRole.values());
} else {
return Multi.createFrom().nothing();
}
})
.map(userRole -> Role.builder().name(userRole).build())
.onItem().transformToUniAndConcatenate(role -> Panache.withTransaction(role::persist))
.subscribe().with(subscription -> LOGGER.infov("Persisting: {0}", subscription));
}
Не тестировал это. Но это должно дать вам какое-то представление.
Multi<Role> savedRoles = Role.existsRoleSeed()
.onItem().transformToMulti(exists -> {
if (!exists) {
return Multi.createFrom().items(Role.UserRole.values());
}
return Multi.createFrom().nothing();
})
.map(userRole -> Role.builder().name(userRole).build())
.onItem().transformToUniAndMerge(role -> Panache.<Role>withTransaction(role::persist));