为啥不使用存储库返回部分域模型结果 [关闭]

Posted

技术标签:

【中文标题】为啥不使用存储库返回部分域模型结果 [关闭]【英文标题】:Why not use a repository to return partial domain model results [closed]为什么不使用存储库返回部分域模型结果 [关闭] 【发布时间】:2018-10-02 10:27:19 【问题描述】:

我看到一些文章指出,存储库应该只为方法调用(例如 GetAll())返回完整的域模型。但是,如果我只需要一个列表,其中每个项目仅由具有 30 个属性的域模型中的 2 个属性组成,该怎么办?我想显示一个列表部门,其中列表只显示部门名称和位置。从该列表中,用户可以选择一个部门并请求其详细信息。从那里我可以进行另一个存储库调用,以返回所选内容的完整域模型,并允许进行典型的 crud 操作。

但是,如果我不应该使用存储库来返回完整域模型的子集,那么建议的方法是什么?我想我可以只返回一个完整的域模型列表,但这似乎浪费了网络带宽,通过我不会使用的线路传输这么多数据。如果我创建另一个模型来表示感兴趣的 2 个属性,这似乎是另一个需要做的大量工作,因为每个模型都有自己的存储库和用于存储库访问的服务模块。

从存储库中检索完整域模型子集的建议方法是什么?此外,如果我违反仅提取完整模型的规则,同时提取仅用于选择列表的部分模型数据,我看不出会发生什么。

【问题讨论】:

【参考方案1】:

在我看来,这可以被认为是一个非常主观的问题......我的建议是基于DDD实践。

DDD 的上下文中,存储库应始终返回一个域对象(即Aggregate)。 聚合是数据存储传输的基本元素 - 您请求加载或保存整个聚合。 应用层将数据转换为对视图有意义的模型 /DTO

解决您的疑虑:

    您描述的选择列表示例非常适合 DTO。如果您创建一个 DTO 来表示两个属性以支持一个视图,那么您就是在创建一个 POCO 对象。这个对象是轻量级的并且创建起来很便宜。您可以使用 AutoMapper 等工具来辅助 DTO 和域模型之间的映射。当需要更改视图时,您的更改通常与 DTO 对象及其映射隔离。您还没有通过应用程序层将视图的概念泄漏到域层中。

    DTO 将减少请求客户端的带宽成本(即,您不会返回具有 30 个属性的域实体并公开显示您的实体

    您可以使用单个存储库来支持您的部门选择列表 Department 实体的视图和 CRUD 操作。

    使用一种域模型。但是,创建您需要支持来自该域模型或模型的视图的尽可能多的 DTO。

说到底,DDD 并不便宜,也不是灵丹妙药。

如果您有一个简单的问题要解决,请使用简单的 CRUD 和对您有意义的模型。这些只是指导方针...

DDD 对开发极其重要的软件很有意义 复杂性(有很多相关的业务规则)。和/或软件 有明确的未来,领域模型可以比 基础设施,或业务需求快速变化的地方。在 其他情况 DDD 可能带来比解决更多的意外复杂性。


对于它的价值,这里有一些关于 DDD 概念的补充说明,希望能有所帮助:

用例最优存储库查询:

Vaughn Vernon 将模式Use Case optimal Repository Queries 描述为...... 与其读取多个不同类型的完整 Aggregate 实例,然后以编程方式将它们组合到单个容器中 (DTO or DPO),不如使用所谓的用例优化查询。这是您使用查找器查询方法设计存储库的地方,该方法将自定义对象组合为一个或多个Aggregate 实例的超集。查询动态地将结果放入Value Object (DDD) 中,专门设计用于满足用例的需求。

您设计的是值对象而不是 DTO,因为查询是域 特定的,而不是特定于应用程序的(例如 DTOS)。自定义使用 然后视图渲染直接使用案例最佳值对象。

这是使用CQRS的类似方法;但是,存储库是在您的统一域模型存储上执行的,而不是旨在支持您的只读视图的数据库。

沃恩弗农还说:

如果你发现必须创建很多finder方法来支持 多个存储库上的用例优化查询,它可能是一个 代码味道。

这可能是因为您误判了聚合边界并忽略了设计一个或多个不同类型聚合的机会。

Vaughn 将这种代码异味描述为:存储库掩码聚合错误设计

这也可能表明需要考虑使用CQRS

DDD 查询模型(又名读取模型)

查询模型是非规范化的数据模型。它仅用于显示数据,而不是用于提供域行为。沃恩弗农说:

如果这种数据模型是 SQL 数据库,那么每个表都会保存 一种客户端视图(显示)的数据。表可以有 许多列,甚至是任何给定用户所需的列的子集 界面显示视图。表视图可以从表中创建,每个 其中用作整体的逻辑子集。

他还声明根据需要创建对许多视图的支持。值得注意的是,基于CQRS 的视图既便宜又一次性(用于开发和维护)。使用Event Sourcing,这种方法效果很好。

DDD DTO:

一种方法是让您的应用程序层组装DTOsDTO 将是您的域实体的子集的投影,以满足您的视图。

Vaughn Vernon 简单地说 -

DTO 旨在保存所有需要 显示在视图中

DDD 存储库

Martin Fowler 将存储库模式描述为:

在域和数据映射层之间使用 用于访问域对象的类集合接口。

请参考这些 SO 问题:

DDD: Should a Dto Assembler be a part of Domain Layer?

Should the repository layer return data-transfer-objects (DTO)?

【讨论】:

我可以看 Vaughn Vernon 的哪些书来了解更多关于上述参考点的信息? @Robertcode 查看以下内容:Vaughn Vernon 的实施领域驱动设计和 Eric Evans 的领域驱动设计:解决软件核心的复杂性

以上是关于为啥不使用存储库返回部分域模型结果 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

我的 dll 中没有资源。但为啥我的 dll 中的 .rdata 部分如此之大? [关闭]

为啥我不能从 github 克隆/提取整个存储库,只有 README 文件? [关闭]

“FromSql”操作的结果中不存在所需的列

存储库模式:DAL 或 BLL [关闭]

为啥 deeplab v3+ 模型对图像边界外的像素感到困惑?

为啥安装软件要关闭网络?