聚合到JPA实体的映射

问题描述 投票:0回答:1

在我参与的DDD项目中,我们正在寻找一些方便的解决方案,以将entity objects映射到domain 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 KeyProductJpaEntity。似乎检测到新的或已删除的ProductBacklogItems的唯一方法是按Primary Key进行匹配。但是,主键不属于域模型...

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

存在哪些解决方案可以解决此问题,而又不会在Domain&Data模型上做出太多牺牲?

java jpa domain-driven-design ddd-repositories
1个回答
0
投票

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

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

实体视图也可以是可更新和/或可创建的”,即支持回冲更改,可以将其用作DDD设计的基础。可更新的实体视图实现脏状态跟踪。您可以内省实际的更改或刷新更改的值。

您可以将可更新的实体视图定义为抽象类,以隐藏“具体实施方式”,例如受保护修饰符后面的主键是这样的:

@@ UpdatableEntityView@EntityView(ProductJpaEntity.class)公共抽象类产品扩展了聚合{@IdMapping受保护的抽象ProductId getProductId();公共抽象集getBacklogItems();}@UpdatableEntityView@EntityView(ProductBacklogItemJpaEntity.class)公共抽象类ProductBacklogItem扩展DomainEntity {@IdMapping受保护的抽象BacklogItemId getBacklogItemId();受保护的抽象ProductId getProductId();公共抽象int getOrdering();}

查询是将实体视图应用于查询的问题,最简单的方法就是按id查询。

Product p = entityViewManager.find(entityManager, Product.class, id);

保存也就是冲洗更改也很容易

entityViewManager.save(entityManager, product);

Spring Data集成使您几乎可以像Spring Data Projections:https://persistence.blazebit.com/documentation/1.4/entity-view/manual/en_US/#spring-data-features一样使用它;对于刷新更改,您可以在存储库中定义一个save方法以接受可更新的实体视图

© www.soinside.com 2019 - 2024. All rights reserved.