【问题标题】:Is it possible to inject too many repositories into a controller?是否可以将太多存储库注入控制器?
【发布时间】:2011-09-15 12:08:24
【问题描述】:

我正在使用 MVC3 开发第一个大型解决方案。我正在使用 ViewModel、AutoMapper 和 DI。

为了为一些更复杂的编辑/创建创建我的 ViewModel,我注入了 10 个左右
存储库。对于除一个存储库之外的所有存储库,它们仅用于获取数据以填充 ViewModel 上的选择列表,因为我只是获取关联的 FK 实体等。

我看到它提到注入大量存储库是不好的做法,我应该重构。多少比多少?这对很多人来说?我应该如何重构?我应该创建一个返回选择列表等的专用服务吗?

这里举个例子是我的RequirementsAndOffer控制器的构造函数

       public RequirementsAndOfferController(
IdefaultnoteRepository defaultnoteRepository, 
IcontractformsRepository contractformsRepository, 
IperiodRepository periodRepository, 
IworkscopeRepository workscopeRepository, 
IcontactRepository contactRepository, 
IlocationRepository locationRepository, 
IrequirementRepository requirementRepository, 
IContractorRepository contractRepository, 
IcompanyRepository companyRepository, 
IcontractRepository contractRepository, 
IrequirementcontracttypeRepository requirementcontracttypeRepository, 
IoffercontractRepository offercontractRepository)

除了我用来获取需求和报价的 requirementsRepository 和 offercontractRepository 之外,以上所有内容都填充了选择。


更新 一般的想法和更新。 Mark Seemann 关于过度注入的博客文章鼓励我考虑这个问题。我特别感兴趣的是存储库以及为什么我必须注入这个数字。我认为在考虑了我的设计之后,我显然没有为每个聚合根使用一个存储库(根据 DDD)。

例如,我有汽车,汽车有租赁合同,租赁合同有租赁期。

我正在为汽车、租赁合同和租赁期创建一个存储库。所以当我认为应该只有一个时,这就是创建 3 个存储库。没有汽车,租用合同和期限就无法存在。因此,我以这种方式减少了一些存储库。

我仍然有一些复杂的表单(客户需要这些大型表单),这些表单需要控制器中的多个存储库。这可能是因为我没有足够的重构。据我所知,虽然我需要单独的存储库来获取选择列表。

我正在考虑创建某种服务的选项,该服务将提供我需要的所有选择列表。这是好习惯/坏习惯吗?我的服务是否应该只针对聚合根?如果是这样,让一项服务提供选择将是错误的。然而,选择似乎确实是同一类型的东西,并且将它们组合在一起在某些方面很有吸引力。

看来我的问题类似于how-to-deal-with-constructor-over-injection-in-net

我想我现在更多的是寻找关于选择列表服务是好还是坏的具体建议。

任何建议表示赞赏。

【问题讨论】:

  • 我认为这里的问题与您的域设计有关。在 DDD(领域驱动设计)中,您不必为领域中的每个实体都有一个存储库。有一个聚合的概念,其中几个域类型被组合到一个聚合中,其中一种类型被降级为根。然后,您将为每个聚合创建一个存储库。我建议阅读这本迷你书,了解 DDD infoq.com/minibooks/domain-driven-design-quickly 的精彩介绍。
  • 感谢收到这本书。我确实想知道这是否是一个问题,因为我已经看到很多关于聚合根的讨论。然而,最终用户可以直接添加/创建/编辑等存储库的所有内容。尽管其中许多主要用于填充各种视图上的选择列表。例如,我有一个作为实体的位置,并且各种实体都有与之关联的位置,所以它需要一个自己的存储库以便人们可以添加位置等似乎是合乎逻辑的?
  • 由于我在您设计的领域没有经验,很遗憾我无法提供有关设计的直接 cmets。但作为一个例子,让我们看看合同和期间。对我来说,一个时期本身并不存在——我认为它是一个价值对象——而是合同的一部分。因此,合同可以是聚合根,而 period 是该聚合的子节点。然后我会通过合同在这段时间内工作。您将有一个合同存储库来处理合同和期限。当然,根据您的域,情况可能并非如此。
  • 另外,如果您想要更快的 DDD 指南并了解 DDD 的各个组件,请查看来自 MSDN 杂志 msdn.microsoft.com/en-us/magazine/dd419654.aspx#id0090074 的这篇文章
  • 是的,我会重新阅读 DDD 的内容,看看是否应该减少存储库的数量。

标签: asp.net-mvc-3 dependency-injection repository viewmodel repository-pattern


【解决方案1】:

从存储库模式开始,您有正确的想法。根据您使用存储库的方式,我完全理解您最终可能会得到很多(每个数据库表甚至可能 1 个。)

您必须判断自己的规范和业务需求,但也许您可以考虑业务层或服务层。

业务层

这一层可能由业务对象组成,这些业务对象封装了您的视图模型(以及固有的视图)的一个或多个意图。您没有描述您的任何领域,但可能是用户的业务对象 可以包括一些 CRUD 方法。然后,您的视图模型将依赖这些业务对象,而不是直接调用存储库方法。您可能已经猜到重构会将对存储库方法的调用转移到业务对象中

服务层

服务层甚至可以使用上面描述的一些业务对象,但也许您可以设计某种类型的消息传递协议/系统/标准来在您的 Web 应用程序和运行在服务器上的 WCF 服务之间进行通信以控制某种。

这不是最具描述性的示例,但我希望它对重构选项的高层次视图有所帮助。

【讨论】:

  • 也许我的问题是我如何使用存储库?基本上,我为每个要使用的实体都有一个。这些中的每一个都是需要的,以便人们可以为每个实体执行 CRUD 操作。例如。编辑可能的合同类型等。我已经为每个存储库实现了一个 GetSelectList。所以我想基本上有一个 SelectList 服务,它消耗所有适当的存储库,然后只返回选择列表。然后我可以注入选择列表服务而不是大量的存储库。但是,这只会将存储库注入从控制器中移除。
  • @GraemeMiller 在非平凡的应用程序中,无论如何执行 CRUD 都不是控制器的责任。因此,即使是这种重构也可以证明是有益的,在语义上更正确,并且可以分离另一个问题。
  • 谢谢。抱歉,我的意思是控制器只是返回视图模型以允许人们进行 CRUD。执行此操作的所有实际操作都在适当的存储库中。
  • 遵循各种建议,将存储库重写为基于聚合根。然后接受您/Marks 的建议并根据根源实施聚合服务。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-09-12
  • 1970-01-01
  • 2012-01-27
  • 1970-01-01
  • 2021-10-06
  • 2011-11-10
  • 2011-01-20
相关资源
最近更新 更多