问题描述
我正在根据领域驱动设计开发一个应用程序。出于这个原因,我提取的实体被映射到域模型。对此域模型的修改可能需要更新,因此我将域模型映射回实体(新实例)并尝试保留它。这是 Hibernate 用 PersistentObjectException 拍我的手腕的时候:
分离实体传递给持久化
我试图在 Spring Boot 应用程序中重现这个问题,但由于某种原因,Spring 将新的实体实例连接到附加的实例。 (或者看起来是这样。)
总结:实体(附加)->模型->实体(分离)
https://gitlab.com/rmvanderspek/quarkus-multithreading/-/tree/persistence
更新:以下是“诀窍”,但它是一种解决方法,感觉可能会有我没有讨价还价的副作用:
entity = respository.getEntityManager().merge(entity);
repository.persist(entity);
解决方法
问题是当实体具有生成的 id,但您在通过构造函数创建的新实例上设置值时。此类实体必须使用 merge
将更改应用于持久状态。另一种方法是首先使用 entityManager.find()
来检索托管实体并将更改应用于该对象。
我认为这是 Blaze-Persistence Entity Views 的完美用例。
我创建了该库以允许在 JPA 模型和自定义接口或抽象类定义的模型之间轻松映射,例如类固醇上的 Spring Data Projections。这个想法是,您可以按照自己喜欢的方式定义目标结构(域模型),并通过 JPQL 表达式将属性(getter)映射到实体模型。
使用 Blaze-Persistence Entity-Views 的 DTO/域模型可能如下所示:
@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();
}