我正在尝试通过spring引导和域驱动设计来构建应用程序。我有一个关于域模型(与表DB的字段匹配(和视图模型(响应API(的问题。
领域模型:
例如:class名称
@Getter
@NoArgsConstructor
@AllArgsConstructor
class Name {
String value;
}
class产品
@Getter
@NoArgsConstructor
@AllArgsConstructor
class Product{
Name name;
}
ViewModel:
@Data
@NoArgsConstructor
@AllArgsConstructor
class ProductView {
//int prodId;
String prodName;
}
按类选择数据DB产品,按类选择响应API生成器ProductView。当从DomainModel转换为ViewModel或反之亦然时,我在ProductView中为此编写了静态方法。它将变成:
@Data
@NoArgsConstructor
@AllArgsConstructor
class ProductView {
//int prodId;
String prodName;
public static ProductView of(Product prod) {
String productName = prod.getName().getValue();
return new ProductView(productName)
}
}
它运行良好,但当数据变得更多时。我认为需要将其作为CommonConvert从DomainModel转换为 ViewModel我有一个使用Mapstruct库的解决方案。但Mapstruct只支持转换相同类型的字段(String with String,ex(。编写CommonConvert的最佳解决方案是什么?
我的建议:不要查询域模型,并将它们转换为视图模型以供阅读。
域模型类(例如聚合(用于表示业务数据和行为,目的是在创建或更改此类业务实体时遵守业务不变量。
为了从持久数据构建视图模型,您可以-在我看来,您应该-绕过域模型。您可以根据需要安全地从数据库中读取数据,而无需经过域存储库。
这是可以的,因为您不能仅仅通过读取数据来违反业务规则。对于编写数据,请通过域存储库和聚合。
在您的情况下,您当然可以使用JPA注释来使用视图模型实体,方法是将这些类设计为完全符合您的查看需求。请记住,视图模型通常和域模型不相关,因为它们可能只需要数据的子集或来自不同聚合的聚合数据。
另一个问题是,如果您需要查询许多对象以进行查看,那么如果您通过存储库查询完整的域聚合,则会很快导致性能问题。由于这样的聚合总是从其子实体和值对象加载所有数据,以便使用所有不变量执行业务逻辑,因此您最终会执行许多昂贵的查询,这些查询适合于加载单个聚合,但不能同时加载许多聚合。
因此,通过只查询您需要查看的内容,您还可以解决此类性能问题。
当遵循DDD时,您通常应该在一个业务事务中只创建或更改一个聚合。因此,域模型不适合查询优化,而适合在编写业务数据时保持业务不变量
视图模型和相应的查询经过优化,可读取并收集所需的所有数据。
简单地映射如下(使用mapstruct(:
@Mapping(source = "name.value", target = "prodName")
public abstract ProductView toProductView(Product model);