Quarkus:如何用新实例更新实体?

Quarkus: how to update an entity with a new instance?

我正在根据领域驱动设计开发一个应用程序。出于这个原因,我获取的实体被映射到域模型。对该域模型的修改可能必须更新,因此我将域模型映射回实体(新实例)并尝试保留它。这是 Hibernate 用 PersistentObjectException 拍我手腕的时候:

detached entity passed to persist

我试图在 Spring 引导应用程序中重现此问题,但由于某种原因 Spring 将新实体实例连接到附加实例。 (或者看起来是这样。)

总结:实体(附加)-> 模型-> 实体(分离)

这里我有一个面临同样问题的简单示例项目:

https://gitlab.com/rmvanderspek/quarkus-multithreading/-/tree/persistence

更新:以下 'the trick',但它是一种解决方法,感觉可能会有我没有讨价还价的副作用:

entity = respository.getEntityManager().merge(entity);
repository.persist(entity);

问题是当一个实体有一个生成的 id,但是你在一个通过构造函数创建的新实例上设置了一个值。此类实体必须使用 merge 将更改应用到持久状态。另一种方法是首先使用 entityManager.find() 来检索托管实体并将更改应用于该对象。

我认为这是 Blaze-Persistence Entity Views 的完美用例。

我创建了库以允许在 JPA 模型和自定义接口或抽象 class 定义的模型之间轻松映射,类似于 Spring 类固醇数据投影。这个想法是您按照自己喜欢的方式定义目标结构(领域模型),并通过 JPQL 表达式将属性(getter)映射到实体模型。

一个 DTO/domain 模型与 Blaze-Persistence 实体视图如下所示:

@EntityView(User.class)
@UpdatableEntityView
public interface UserDto {
    @IdMapping
    Long getId();
    String getName();
    void setName(String name);
    @UpdatableMapping
    Set<RoleDto> getRoles();

    @EntityView(Role.class)
    interface RoleDto {
        @IdMapping
        Long getId();
        String getName();
    }
}

查询就是将实体视图应用于查询,最简单的就是通过 id 进行查询。

UserDto user = entityViewManager.find(entityManager, UserDto.class, id);
user.getRoles().add(entityViewManager.getReference(RoleDto.class, roleId));
entityViewManager.save(entityManager, user);

这只会刷新实际更改的数据,并避免不必要的加载。

Quarkus 和 JAX-RS 集成使得在您的应用程序中使用它变得超级简单:https://persistence.blazebit.com/documentation/entity-view/manual/en_US/#jaxrs-integration

    @POST
    @Path("/users/{id}")
    @Consumes(MediaType.APPLICATION_JSON)
    @Transactional
    public Response updateUser(@EntityViewId("id") UserDto user) {
        entityViewManager.save(entityManager, user);

        return Response.ok(user.getId().toString()).build();
    }