具有多个实体的存储库创建DTO

时间:2015-11-01 15:29:12

标签: c# asp.net-web-api architecture domain-driven-design repository-pattern

在此处进行一些C#代码审查,并注意到开发人员正在与另外5个表进行连接,并在DTO中进行内联IQueryable投影。在存储库中加入的表是用户约会 CommunicationPreference UserProduct 产品< / strong>即可。我没有设计系统,我可能在某种程度上简化了它,但是现在就让我们按照这个原则进行操作。使用实体框架和Web API。

这有点长,所以我道歉,但真的好奇听到别人对这件事的看法。

因此,这些表的相关之处在于每个用户都有一个即将到来的服务约会列表来为其产品提供服务。 UserProduct表显示产品和用户之间的关系,product表显示产品的种类。 CommunicationPreference处理他们希望如何联系他们的服务,例如他们的服务何时到期,是否有人来服务产品,他们希望如何联系(电话电子邮件文本等)。

所以开发人员将这些表连接在存储库本身,然后创建一个名为“UserServiceOverviewDto”的DTO,它返回到控制器然后返回到前端,并且基本上有信息以网格形式显示给客户代表(谁用户是,即将到来的约会,什么产品等基本上我刚才写的所有内容。)

我理解为什么他们这样做 - 而不是对5个不同的存储库进行5次调用,而是将它们全部合二为一,然后不必将每个存储器转换为DTO,而是一次性完成所有操作。但我知道存储库也不应该返回DTO。理想情况下,您的存储库应返回逻辑上聚合的内容,并代表解决您问题的一个实体。

在我考虑这个问题的时候,我在SO What type to return when querying multiple entities in Repository layer?中偶然发现了这个问题,但这对我没有多大帮助,并且想要就如何做更多的建议。

从DDD的角度来看,我想知道需要引入什么新的“东西”。也许我需要创建一个新的上下文/存储库,这是一个新的东西。如果我试图说这是一个常见的分组,并给它一个像“X”的名称这是否意味着我想创建一个新的数据库表来表示?可能不是,因为我已经有了存储这些信息的表格。

这是否意味着我想创建一个名为“X”的新类而没有相应的数据库表?那么这与DTO有何不同?实际上,它几乎暗示通过创建这个类,我试图通过实例化X而不是XDto来使我的存储库更纯粹,然后将X转换为服务层中的DTO(除了转移之外我还没有获得任何东西周围的东西,并创造一个非常贫穷的实体)。

总而言之,问题是:

如果我为了方便起见而将多个实体组合在一起,那么最好是:

  1. 让服务层进行5次不同的数据库调用,并在此层组装DTO以返回控制器?这不是坏事吗? 5个电话只是为了让我的代码看起来更“纯粹”?一次性完成连接并从数据库中获取所需内容不是更好吗?
  2. 在C#中创建一个表示这5个表的结合的新类,然后在该类和相应的DTO之间实现映射。如上所述,这堂课不会坚持下去。
  3. 让存储库执行其连接以创建新的DTO作为内联投影(似乎错误的b / c存储库应返回实体而不是DTO)
  4. 真的很期待这里的一些反馈!谢谢!

3 个答案:

答案 0 :(得分:4)

这个问题并非特定于CQRS,并且在其之外也有效,所以我会这样回答。

您描述的情况通常在实施统计功能时发生。例如。回答诸如“订购此产品的用户数量,按天分组?”等问题。这有时称为用例最佳查询

在这些情况下,您建议的第二种方法通常是最好的。 创建一个为此类操作的结果建模的新类型。聚合存储库中的所有数据并返回该类型的实例。

解决方案#1通常非常效率低,因为服务层无法使用数据库提供的聚合和分组功能。解决方案#3违反了单一责任原则,迟早会导致可维护性问题。

新类型的设计注意事项

  • 返回的数据始终是只读的,因此类型可以建模为值对象
  • 如果类型在域中具有含义,请将其放在域层中。如果没有,请将其放在持久层中。

答案 1 :(得分:0)

看一下CQRS,这几乎是对这个主题的精确讨论。基本上,您应该创建一个新对象来表示此聚合,但要知道这样做会给项目带来很大的复杂性。您创建的这个东西无法更新/持久化,只能查询它。更新与其关联的其他实体必须通过单独的域模型完成。

答案 2 :(得分:0)

除了这里的答案,我还会研究一下您的应用程序的数据缓存。它可以通过在应用程序中缓存对象来提供一个很好的解决方案,减少数据库命中,同时不会实现CQRS。

我肯定会使用像memcached,redis,AppFabric或内置的.NET MemoryCache等内容来在用户登录时自动缓存用户的通信首选项和内存中的用户对象等内容。

您还可以使用数据缓存将公司的产品缓存到内存中。更新,删除产品等时,您必须使缓存项无效