Quarkus:如何将方法从命令式更改为反应式

Quarkus: How to change a method from imperative to reactive

我构建了一个小的 Rest API 来了解更多关于 Quarkus 框架的信息。现在我想开始使用该框架及其反应性 API 但我正在努力理解一些概念。目前该项目正在使用 RESTEasy Reactive with Jackson、Hibernate Reactive with 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 -> {
                });
    }

当我 运行 应用程序时,它没有给出任何错误,日志显示发生了一些事情,数据库创建了 table,但是它没有插入任何东西。我尝试过不同的方法,但是,我没有成功地让它像我希望的那样工作。

还没有测试过这个。但这应该会给你一些想法。

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));

根据@Haroon 的回答和@Clement 的评论,我做了以下操作

  • 删除了 @ReactiveTransactional 作为我的方法 returns 无效并且不在 REST 边界上
  • 因为我删除了注释,所以我需要使用 Panache.withTransaction 方法
  • 最后在方法中我订阅了 multi

请注意,我将 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));
    }