DDD - 存储库是否可以通过标识符之外的其他内容获取聚合?

时间:2012-12-08 14:19:57

标签: domain-driven-design ddd-repositories

我将用户建模为聚合根,用户由标识符值对象和电子邮件值对象组成。两个值对象都可以唯一地标识用户,但是允许更改电子邮件而标识符不能更改。

在我看到的大多数DDD示例中,聚合根的存储库仅按标识符提取。添加另一个通过电子邮件获取到存储库的方法是否正确?我这个造型很差吗?

5 个答案:

答案 0 :(得分:1)

我会说是的,存储库有适合通过身份以外的方式检索聚合的方法。但是,有一些细微之处需要注意。

许多存储库示例仅通过ID检索的原因是基于观察到存储库与聚合结构相结合无法满足所有查询要求。例如,如果您有一个查询来调用聚合中的某些字段以及引用的聚合和一些摘要数据的某些字段,则相应的聚合类不能用于表示此数据。相反,需要专用的read-model。因此,查询职责与存储库分离。这有几个优点(查询可以由专门的非规范化商店提供),它是CQRS的主要范例。在这种类型的体系结构中,只有在需要执行某些行为时,才会由存储库检索域类。所有只读用例都由读模型提供。

我认为适合存储库使用GetByEmail方法的原因是基于YAGNI并且与复杂性作斗争。随着需求的变化和发展,您可以允许应用程序发展。您不需要立即跳转到CQRS并分开读/写存储。您可以从也恰好具有查询方法的存储库开始。唯一要记住的是,当您需要在这些实体上调用某些行为时,您应该尝试按ID检索实体。

答案 1 :(得分:0)

我会将此功能放入特定于您的User对象的服务/业务层。并非每个对象都有电子邮件标识符。这看起来更像是业务逻辑而不是存储库的责任。我相信你已经知道了,但是here很好地解释了我所说的内容。

我不建议这样做,但您可以为公开a GetByEmail(string emailAddress)方法的用户提供存储库的特定实现,但我仍然喜欢这个服务理念。

答案 2 :(得分:0)

我同意eulerfx的回答:

  

你需要问问自己为什么需要使用某些东西获得AR   除了身份证。

我认为很明显,拥有ID,但 还有其他唯一标识符,例如电子邮件地址。

如果您使用CQRS,则需要首先确定数据对域是重要还是仅对查询存储很重要。如果您要求数据100%一致,那么它会略微改变。例如,如果要检查是否存在电子邮件地址以满足唯一约束,则需要100%一致性。如果查询的数据在任何时候都是陈旧的,您可能会遇到问题。

请记住,存储库代表一系列排序。因此,如果您不需要实际操作AR(命令端),但您已经确定使用域名的位置是合适的,那么您可以始终在存储库中找到ContainsEMailAddress;否则,您的域数据存储也可以有一个查询端,因为您的域数据存储(OLTP类型存储)是100%一致的,而您的查询存储(OLAP类型存储)可能只是最终一致,这是典型的CQRS与单独的查询商店。

答案 3 :(得分:0)

添加另一个通过电子邮件提取到存储库的方法是否正确? - 我不会这样做。在我看来,存储库应该只有通过id,save和delete获取的方法。

我宁愿问你为什么在命令处理程序中没有用户id,你要在其中获取用户并在其上调用域方法。我不知道你到底在做什么,但对于登录/注册场景,我会做以下。当用户登录时,他会传递一个电子邮件地址和一个密码,然后您进行查询以对用户进行身份验证 - 这不会使用域或存储库(仅用于命令),但会使用某些查询实现,这将返回一些UserDto包含用户ID,从这一点上你就拥有了用户ID。下一个场景是注册。创建新用户的命令处理程序将创建一个新的用户实体,然后用户需要登录。

答案 4 :(得分:0)

  

在DDD的大多数示例中,我看到了一个聚合的存储库   root只按标识符提取。

我很想知道你看过的例子。根据DDD definition,存储库是

  

封装存储,检索搜索行为的机制   它模仿了一组对象。

搜索显然包括通过各种标准获取根或根集合,而不仅仅是其ID。

存储库是GetCustomerByEmail()GetCustomersOver18()GetCustomersByCountry(...)等的理想之地。