简体   繁体   中英

How to correctly handle DTO conversion in Micronaut Reactive

Lets say we are working with Micronaut Reactive (Project Reactor) and we would like to create a user account. SignUp DTO is represented by the following Kotlin class:

@Introspected
data class SignUpDto(
    @field:Schema(example = "admin")
    @field:NotBlank @field:Max(value = 255) var username: String? = null,

    // rest is omitted for brevity
)

In order to create and persist an account entity in the database, first, we have to convert the SignUpDTO to the account entity represented by the kotlin class below:

@Entity(name = "Accounts")
@Where("@.active = true")
open class AccountEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "accounts_sequence_generator")
    @SequenceGenerator(name = "accounts_sequence_generator", sequenceName = "sequence_accounts")
    @Column(name = "id", nullable = false, unique = true)
    open var id: Long? = null

    @Column(name = "username", nullable = false, unique = true, updatable = false, length = 255)
    open var username: String? = null

    @Column(name = "active", nullable = false)
    open var active: Boolean? = true

    @ManyToMany(fetch = FetchType.LAZY, cascade = [CascadeType.PERSIST, CascadeType.MERGE])
    @JoinTable(name = "accounts_roles",
        joinColumns = [JoinColumn(name = "accounts", referencedColumnName = "id")],
        inverseJoinColumns = [JoinColumn(name = "roles", referencedColumnName = "id")])
    open var roles: MutableSet<RoleEntity> = mutableSetOf()

    // rest is omitted for brevity
}

As you can see, AccountEntity has a many-to-many relationship on a RoleEntity. For completeness, RoleEntity is shown below:

@Entity(name = "Roles")
open class RoleEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    @Column(name = "id", nullable = false, unique = true)
    open var id: Long? = null

    @Column(name = "role", nullable = false, unique = true)
    @Enumerated(EnumType.STRING)
    open var role: Role? = null

    @Column(name = "description", nullable = false, length = 500)
    open var description: String? = null

    // rest is omitted for brevity
}

Application defines a RoleRepository as follows:

@Repository
interface RoleRepository : ReactorCrudRepository<RoleEntity, Long> {
    fun findByRole(role: Role): Mono<RoleEntity>
}

We are interested in mapping a SignUpDTO request to an account entity and persisting that entity in a reactive way. Function that does the converting is given below:

fun convertSignUpToAccountEntity(@Valid signUpDto: SignUpDto): AccountEntity {
        return AccountEntity().apply {
            this.username = signUpDto.username
            this.active = true
            this.roles.add(**add a user role here**)
        }
}

Given that the RoleRepository is available to this function, how would one fetch the Role.User entity and add it to the list of account roles in a reactive way, since calling block just indefinitely blocks the calling thread? Is there a way to handle this in a reactive way?

You can have something like this:

return Flux.fromIterable(Arrays.asList("role1", "role2"))
            .flatMap(role -> roleRepository.findByRole(role))
            .collectList()
            .map(roles -> convertSignUpToAccountEntity(signUpDto, roles))
            .flatMap(accountEntityRepository::save);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM