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

     2023-02-24     257

关键词:

【中文标题】为啥不使用存储库返回部分域模型结果 [关闭]【英文标题】: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 的领域驱动设计:解决软件核心的复杂性

Doctrine 存储库返回空结果集

...1110:05:49【问题描述】:Doctrine存储库存在真正问题。即使使用findAll()方法,它也会返回一个空结果集。表中有条目,生成的SQL运行良好。其他存储库工作正常。没有错误消息/异常-只是一个空的结果集。扯掉我的头发。使用Doctrin... 查看详情

为啥调用存储过程不返回任何东西?

】为啥调用存储过程不返回任何东西?【英文标题】:Whycallingastoredproceduredoesnotreturnanything?为什么调用存储过程不返回任何东西?【发布时间】:2015-03-0906:09:10【问题描述】:我用in参数创建了一个存储过程。当我将此过程称为... 查看详情

为啥 MFCC 提取库返回不同的值?

】为啥MFCC提取库返回不同的值?【英文标题】:WhydoMFCCextractionlibsreturndifferentvalues?为什么MFCC提取库返回不同的值?【发布时间】:2019-02-0607:04:08【问题描述】:我正在使用两个不同的库提取MFCC特征:python_speech_features库BOB库但... 查看详情

存储库、管道、业务逻辑和域模型 - 我如何将它们组合在一起?

...了一个您可能有解决方案的难题。表示层是MVC。我的ORM是使用LinqToSQL执行的-它是一个单独的项目,为存储库提供服务。每个存储 查看详情

无法使用存储过程获得确切的结果,因为它返回带有增量的值[关闭]

】无法使用存储过程获得确切的结果,因为它返回带有增量的值[关闭]【英文标题】:Unabletogettheexactresultusingstoredprocedureasitisreturningthevalueswiththeincrementation[closed]【发布时间】:2020-08-1912:07:16【问题描述】:ALTERPROCEDURESearching(@Empl... 查看详情

为啥 Gradle 不使用插件 pom.xml 中声明的 Maven 存储库?

】为啥Gradle不使用插件pom.xml中声明的Maven存储库?【英文标题】:Whydoesn\'tGradleuseMavenrepositoriesdeclaredintheplug-in\'spom.xml?为什么Gradle不使用插件pom.xml中声明的Maven存储库?【发布时间】:2019-08-1007:18:17【问题描述】:考虑一下我制... 查看详情

为啥 returnValueMap() 返回 NULL

】为啥returnValueMap()返回NULL【英文标题】:WhyreturnValueMap()isreturningNULL为什么returnValueMap()返回NULL【发布时间】:2019-09-2913:05:51【问题描述】:试图在测试中模拟一个学说存储库,当与findOneBy方法一起使用时,returnValueMap()总是返回... 查看详情

为啥Android裁剪意图不返回ActivityResult?

】为啥Android裁剪意图不返回ActivityResult?【英文标题】:Whydoesn\'tAndroidcropintentreturnActivityResult?为什么Android裁剪意图不返回ActivityResult?【发布时间】:2012-02-1901:52:57【问题描述】:我正在尝试从媒体库中裁剪图像。我可以访问... 查看详情

为啥我的 laravel 集合返回 500 错误,即使不是在我使用 dd() 检查结果时?

】为啥我的laravel集合返回500错误,即使不是在我使用dd()检查结果时?【英文标题】:Whyismylaravelcollectionreturning500errorevenit\'snotwhenIcheckedtheresultsusingdd()?为什么我的laravel集合返回500错误,即使不是在我使用dd()检查结果时?【发布... 查看详情

为啥 DNN 中 DAL2 存储库的默认 GetById() 执行缓慢?

】为啥DNN中DAL2存储库的默认GetById()执行缓慢?【英文标题】:WhydoesthedefaultGetById()foraDAL2repositoryinDNNexecuteslowly?为什么DNN中DAL2存储库的默认GetById()执行缓慢?【发布时间】:2013-11-2911:08:18【问题描述】:我遇到了一个问题,即DAL2... 查看详情

Code First 调用存储过程返回多个结果

...布时间】:2012-08-1421:30:46【问题描述】:我在一个项目中使用CodeFirst。项目已经完成了一半。我需要调用一个存储过程来返回多个结果(3个选择)。我的研究告诉我,CodeFirst不支持它。我有什么选择?更改项目以首先使用模型... 查看详情

为啥查询的数据在结果集中返回而不是在数组中?

】为啥查询的数据在结果集中返回而不是在数组中?【英文标题】:Whyisquerieddatareturnedinaresultsetandnotinanarray?为什么查询的数据在结果集中返回而不是在数组中?【发布时间】:2014-07-1614:59:17【问题描述】:为什么大多数编程语... 查看详情

为啥 turfjs 距离返回的结果与 Google Map 几何库 computeDistanceBetween 不同?

】为啥turfjs距离返回的结果与GoogleMap几何库computeDistanceBetween不同?【英文标题】:WhyturfjsdistancereturnsresultsdifferentfromGoogleMapgeometrylibscomputeDistanceBetween?为什么turfjs距离返回的结果与GoogleMap几何库computeDistanceBetween不同?【发布时间... 查看详情

为啥 MySQL 给出错误“不允许从函数返回结果集”?

】为啥MySQL给出错误“不允许从函数返回结果集”?【英文标题】:WhyMySQLisgivingerror"Notallowedtoreturnaresultsetfromafunction"?为什么MySQL给出错误“不允许从函数返回结果集”?【发布时间】:2012-08-0611:52:48【问题描述】:我正... 查看详情

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

...【发布时间】:2016-04-2119:02:02【问题描述】:我刚刚开始使用EF7学习MVC6。我有一个存储过程,我想返回模型中的一部分字段。如果我不返回模型中的每个字段,我会收到“‘FromSql’操作的结果中不存在所需的列‘FirstName’ 查看详情

为啥不建议将 git 存储库放在 Dropbox 文件夹中?

】为啥不建议将git存储库放在Dropbox文件夹中?【英文标题】:WhyisputtinggitrepositoriesinsideofaDropboxfoldernotrecommended?为什么不建议将git存储库放在Dropbox文件夹中?【发布时间】:2013-10-1818:14:36【问题描述】:使用OSX的GitHub应用程序在... 查看详情

springcrudrepositoryfindby*方法没有返回任何结果

我已经实现了扩展CrudRepository的存储库。底层模型(Account)有一个plaidAccountId字段,相应的查询方法是findByPlaidAccountId。最好的我可以告诉我,我已正确连线,因为其他模型上的其他查询正常工作。但是,此查询不返回任何结果... 查看详情

长存储过程在某些 exec 之后停止返回结果,为啥?

】长存储过程在某些exec之后停止返回结果,为啥?【英文标题】:Alongstoredprocedurestopsreturningresultsaftersomeexecs,why?长存储过程在某些exec之后停止返回结果,为什么?【发布时间】:2011-01-2614:54:52【问题描述】:嗨我有一个长存储... 查看详情