聚合到JPA实体的映射 [英] Aggregate to JPA Entity mapping
问题描述
在我参与的 DDD
项目中,我们正在寻找一些便捷的解决方案来映射实体对象
转换为域对象
,反之亦然。
该项目的开发人员同意将域模型与数据模型完全分离。
数据层使用 JPA(休眠)
作为持久性技术。
我们都认为持久性是DDD中的实现细节,从开发人员的角度来看,我们都在寻求应用程序各个方面的最合适解决方案。
我们最担心的是将包含实体
的列表的聚合
映射到一个 JPA实体
,而该实体又包含一个一对多
关系。
看看下面的例子:
域模型
公共类产品扩展了汇总{
private ProductId productId;
private Set< ProductBacklogItem> backlogItems;
//构造函数&为简便起见省略了方法
}
公共类ProductBacklogItem扩展了DomainEntity {
private BacklogItemId backlogItemId;
私人int订购;
private ProductId productId;
//构造函数&为简便起见省略了方法
}
数据模型
公共类ProductJpaEntity {
private String productId;
@OneToMany
private Set< ProductBacklogItemJpaEntity> backlogItems;
//构造函数&为简便起见省略了方法
}
公共类ProductBacklogItemJpaEntity {
private String backlogItemId;
私人int订购;
private String productId;
//构造函数&为简便起见省略了方法
}
存储库
公共接口ProductRepository {
Product findBy(ProductId productId);
无效保存(产品产品);
}
类ProductJpaRepository实现ProductRepository {
@Override
public Product findBy(ProductId productId){
ProductJpaEntity实体= //通过productId
$ b查找实体$ b ProductBacklogItemJpaEntity backlogItemEntities = entity.getBacklogItemEntities();
Set< ProductBacklogItem> backlogItems = toBackLogItems(backlogItemEntities);
返回新产品(新ProductId(entity.getProductId()),backlogItems);
}
@Override
public void save(产品product){
ProductJpaEntity实体= //通过productId
的查找实体if(实体== null){
//将Product和ProductBacklogItems映射到其对应的实体,并保存
返回;
}
Set< ProductBacklogItem> backlogItems = product.getProductBacklogItems();
//我们如何知道哪些backlogItem是:new,deleted或adapted ...?
}
}
当 ProductJpaEntity code>已存在于
DB
中,我们需要更新所有内容。
如果有更新,则 ProductJpaEntity
在Hibernate PersistenceContext
中已经可用。
但是,我们需要找出哪些 ProductBacklogItems
已更改。
更具体地说:
-
ProductBacklogItem
可以被添加到Collection
-
ProductBacklogItem
从集合
$ b中删除$ b
每个 ProductBacklogItemJpaEntity
有一个主键
指向 ProductJpaEntity
。
似乎检测到新的或已删除的 ProductBacklogItems
的唯一方法是通过主键
进行匹配。
但是,主键不属于域模型...
还可以先删除所有 存在哪些解决方案可以解决此问题,而不会在Domain&数据模型? 这是火焰持久性实体视图。 我创建了该库以允许轻松映射在JPA模型和自定义接口或抽象类定义的模型之间,例如类固醇上的Spring Data Projections。想法是您可以按照自己喜欢的方式定义目标结构(域模型),并通过JPQL表达式将属性(获取器)映射到实体模型。 实体视图也可以可更新和/或可创建,即支持回冲更改,可以用作DDD设计的基础。 您可以将可更新的实体视图定义为抽象类,以隐藏实现细节,例如这样的受保护修饰符后面的主键: 查询是将实体视图应用于查询的问题,最简单的方法是 保存即刷新更改也很容易 Spring Data集成使您可以像使用Spring Data Projections一样使用它: https://persistence.blazebit.com/documentation/entity-view/manual/ zh_CN / index.html#spring-data-features 并进行刷新更改,您可以在存储库中定义一个接受可更新实体视图的 In a Developers of this project agreed to fully decouple domain model from data model.
The data layer uses As we all reckon that persistence is an implementation detail in DDD, from a developers' point of view we're all seeking for the most appropriate solution in every aspect of the application. The biggest concern we're having is when an Take a look at the example below: ProductBacklogItemJpaEntity <
ProductJpaEntity
的/ code>实例(存在于数据库中),刷新到数据库,创建新的 ProductBacklogItemJpaEntity
实例并将其保存到数据库。
这将是一个糟糕的解决方案。每次保存产品
都会导致多次删除
和插入
可更新的实体视图实现脏状态跟踪。您可以内省实际的更改或刷新更改的值。
@UpdatableEntityView
@EntityView(ProductJpaEntity.class)
公共抽象类产品扩展了聚合{
@IdMapping
受保护的抽象ProductId getProductId();
公共摘要Set< ProductBacklogItem> getBacklogItems();
}
@UpdatableEntityView
@EntityView(ProductBacklogItemJpaEntity.class)
公共抽象类ProductBacklogItem扩展了DomainEntity {
@IdMapping
受保护的抽象BacklogItemId getBacklogItemId();
受保护的抽象ProductId getProductId();
public abstract int getOrdering();
}
Product p = EntityViewManager.find(entityManager,Product.class,id);
entityViewManager.save(entityManager,产品);
save
方法 p> DDD
-project I'm contributing to, we're seeking for some convenient solutions to map entity objects
to domain objects
and visa versa.JPA (Hibernate)
as persistence technology.aggregate
, containing a list of entities
, is mapped to a JPA entity
that in it's turn contains a one-to-many
relationship.Domain model
public class Product extends Aggregate {
private ProductId productId;
private Set<ProductBacklogItem> backlogItems;
// constructor & methods omitted for brevity
}
public class ProductBacklogItem extends DomainEntity {
private BacklogItemId backlogItemId;
private int ordering;
private ProductId productId;
// constructor & methods omitted for brevity
}
Data model
public class ProductJpaEntity {
private String productId;
@OneToMany
private Set<ProductBacklogItemJpaEntity> backlogItems;
// constructor & methods omitted for brevity
}
public class ProductBacklogItemJpaEntity {
private String backlogItemId;
private int ordering;
private String productId;
// constructor & methods omitted for brevity
}
Repository
public interface ProductRepository {
Product findBy(ProductId productId);
void save(Product product);
}
class ProductJpaRepository implements ProductRepository {
@Override
public Product findBy(ProductId productId) {
ProductJpaEntity entity = // lookup entity by productId
ProductBacklogItemJpaEntity backlogItemEntities = entity.getBacklogItemEntities();
Set<ProductBacklogItem> backlogItems = toBackLogItems(backlogItemEntities);
return new Product(new ProductId(entity.getProductId()), backlogItems);
}
@Override
public void save(Product product) {
ProductJpaEntity entity = // lookup entity by productId
if (entity == null) {
// map Product and ProductBacklogItems to their corresponding entities and save
return;
}
Set<ProductBacklogItem> backlogItems = product.getProductBacklogItems();
// how do we know which backlogItems are: new, deleted or adapted...?
}
}
When a ProductJpaEntity
already exists in DB
, we need to update everything.
In case of an update, ProductJpaEntity
is already available in Hibernate PersistenceContext
.
However, we need to figure out which ProductBacklogItems
are changed.
More specifically:
ProductBacklogItem
could have been added to theCollection
ProductBacklogItem
could have been removed from theCollection
Each ProductBacklogItemJpaEntity
has a Primary Key
pointing to the ProductJpaEntity
.
It seems that the only way to detect new or removed ProductBacklogItems
is to match them by Primary Key
.
However, primary keys don't belong in the domain model...
There's also the possibility to first remove all ProductBacklogItemJpaEntity
instances (which are present in DB) of a ProductJpaEntity
, flush to DB, create new ProductBacklogItemJpaEntity
instances and save them to DB.
This would be a bad solution. Every save of a Product
would lead to several delete
and insert
statements in DB.
Which solution exists to solve this problem without making too many sacrifices on Domain & Data model?
This is a perfect use case for Blaze-Persistence Entity Views.
I created the library to allow easy mapping between JPA models and custom interface or abstract class defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure(domain model) the way you like and map attributes(getters) via JPQL expressions to the entity model.
Entity views can also be updatable and/or creatable i.e. support flushing changes back, which can be used as a basis for a DDD design. Updatable entity views implement dirty state tracking. You can introspect the actual changes or flush changed values.
You can define your updatable entity views as abstract classes to hide "implementation specifics" like e.g. the primary key behind the protected modifier like this:
@UpdatableEntityView
@EntityView(ProductJpaEntity.class)
public abstract class Product extends Aggregate {
@IdMapping
protected abstract ProductId getProductId();
public abstract Set<ProductBacklogItem> getBacklogItems();
}
@UpdatableEntityView
@EntityView(ProductBacklogItemJpaEntity.class)
public abstract class ProductBacklogItem extends DomainEntity {
@IdMapping
protected abstract BacklogItemId getBacklogItemId();
protected abstract ProductId getProductId();
public abstract int getOrdering();
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
Product p = entityViewManager.find(entityManager, Product.class, id);
Saving i.e. flushing changes is easy as well
entityViewManager.save(entityManager, product);
The Spring Data integration allows you to use it almost like Spring Data Projections: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features and for flushing changes, you can define a save
method in your repository that accepts the updatable entity view
这篇关于聚合到JPA实体的映射的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!