gpt4 book ai didi

java - 聚合到 JPA 实体映射

转载 作者:行者123 更新时间:2023-12-04 13:56:22 24 4
gpt4 key购买 nike

DDD -我正在参与的项目,我们正在寻找一些方便的 map 解决方案 entity objectsdomain objects反之亦然。

该项目的开发人员同意将领域模型与数据模型完全解耦。
数据层使用JPA (Hibernate)作为持久化技术。

正如我们都认为持久化是 DDD 中的一个实现细节,从开发人员的角度来看,我们都在寻求应用程序的各个方面最合适的解决方案。

我们最大的担忧是何时出现 aggregate ,包含 entities 的列表, 映射到 JPA entity它又包含一个 one-to-many关系。

看看下面的例子:

领域模型

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
}

数据模型
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
}

存储库
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...?
}
}

ProductJpaEntity已存在于 DB ,我们需要更新一切。
如果有更新, ProductJpaEntity已经在 Hibernate 中可用 PersistenceContext .
但是,我们需要弄清楚是哪个 ProductBacklogItems被改变。

进一步来说:
  • ProductBacklogItem可以添加到 Collection
  • ProductBacklogItem可能已从 Collection 中删除


  • 每个 ProductBacklogItemJpaEntity有一个 Primary Key指向 ProductJpaEntity .
    似乎唯一的方法是检测新的或删除的 ProductBacklogItems是通过 Primary Key 匹配它们.
    但是,主键不属于域模型......

    也有可能首先删除所有 ProductBacklogItemJpaEntity ProductJpaEntity 的实例(存在于数据库中) ,刷新到数据库,创建新 ProductBacklogItemJpaEntity实例并将它们保存到数据库。
    这将是一个糟糕的解决方案。每次保存 Product会导致几个 deleteinsert DB 中的语句。

    有什么解决方案可以在不牺牲领域和数据模型的情况下解决这个问题?

    最佳答案

    这是 Blaze-Persistence Entity Views 的完美用例.

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

    实体 View 也可以是可更新和/或可创建的,即支持刷新更改,这可以用作 DDD 设计的基础。
    可更新的实体 View 实现脏状态跟踪。您可以内省(introspection)实际更改或刷新更改的值。

    您可以将可更新的实体 View 定义为抽象类以隐藏“实现细节”,例如 protected 修饰符后面的主键,如下所示:

    @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();
    }

    查询是将实体 View 应用于查询的问题,最简单的只是按 id 查询。
    Product p = entityViewManager.find(entityManager, Product.class, id);
    保存即刷新更改也很容易
    entityViewManager.save(entityManager, product);
    Spring Data 集成允许您像使用 Spring Data Projections 一样使用它: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features对于刷新更改,您可以定义 save存储库中接受可更新实体 View 的方法

    关于java - 聚合到 JPA 实体映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61541229/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com