Quarkus Reactive Resteasy结合Panache Repository调用persist报错如何解决?
问题解答
方案可行性确认
Quarkus Hibernate Reactive Panache 完全支持 Repository 模式,官方同时提供 Active Record(实体直接继承 Panache 相关基类)和 Repository 两种使用范式,你当前的选型不存在设计问题,可以放心使用。
报错原因与修复方案
核心报错原因
编译报错和IDE的persist方法提示错误分别来自两个问题:
- 调用
Panache.withTransaction()时参数类型错误:该方法要求传入返回Uni的Supplier函数,你直接传入了repository.persist(resource)的执行结果(类型为Uni<T>),和要求的Supplier<Uni<T>>类型不匹配。 - Repository泛型类型不匹配:
PanacheRepository<T>默认主键类型为Long,你的实体使用UUID作为主键,应该使用支持自定义主键类型的PanacheRepositoryBase<T, UUID>。
另外你同时使用@Transactional注解和手动调用Panache.withTransaction()属于重复配置,响应式场景下二选一即可。
修复后代码
package com.fortuneapp.backend.application.rest import com.fortuneapp.backend.application.domain.core.models.entities.Fruit import io.quarkus.hibernate.reactive.panache.PanacheRepositoryBase import io.smallrye.mutiny.Uni import java.net.URI import java.util.* import javax.transaction.Transactional import javax.validation.Valid import javax.ws.rs.* import javax.ws.rs.core.MediaType import javax.ws.rs.core.Response @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) // 泛型适配UUID主键类型,Repository改用PanacheRepositoryBase open class GenericResource<T>( private val repository: PanacheRepositoryBase<T, UUID>, ) { @GET fun getAll(): Uni<MutableList<T>> = repository.listAll() @POST @Transactional fun add(@Valid resource: T): Uni<Response> = repository.persist(resource) .onItem().transform { persistedEntity -> // 通用场景建议给实体加带getId的公共接口,避免强转Fruit val id = (persistedEntity as Fruit).id Response.created(URI.create("/fruits/$id")).build() } @GET @Path("/{id}") fun get(@PathParam("id") id: UUID): Uni<T> = repository.findById(id) @PUT // 语义上更新操作建议用PUT而非POST @Transactional @Path("/{id}") fun update( @PathParam("id") id: UUID, @Valid resource: T ): Uni<T> = repository.findById(id) .onItem().ifNotNull().invoke { existing -> // 此处补充字段更新逻辑,建议实体实现统一更新接口处理字段赋值 } .onItem().ifNotNull().transformToUni { existing -> repository.persist(existing) } @DELETE @Transactional @Path("/{id}") fun delete(@PathParam("id") id: UUID): Uni<Long> = repository.deleteById(id) }
补充说明
如果需要保留完全的通用性,建议给所有实体定义一个公共接口,暴露getId()方法,避免在通用Resource中做类型强转。
内容的提问来源于stack exchange,提问作者rjjdv
相关产品推荐
相关产品推荐

