DDD - 如何实现高性能的搜索存储库

发布于 2024-08-18 06:38:25 字数 1383 浏览 7 评论 0原文

我有一个关于 DDD 和存储库模式的问题。

假设我有一个客户聚合根的客户存储库。获取& Find 方法返回完全填充的聚合,其中包括 Address 等对象。一切都很好。但是,当用户在用户界面中搜索客户时,我只需要聚合的“摘要” - 只是一个包含摘要信息的平面对象。

处理此问题的一种方法是像平常一样调用存储库上的 find 方法,然后在应用程序层中,将每个客户聚合映射到 CustomerSearchResult / CustomerInfo DTO,并将它们发送回客户端。

但我的问题是性能;每个客户聚合可能需要多个查询来填充所有关联。因此,如果我的搜索条件与 50 个客户相匹配,那么这对数据库来说是相当大的打击,因为它可能会检索我根本不需要的数据。

另一个问题是,我可能希望包含有关客户聚合根边界之外的客户的汇总数据,例如最后订单的日期。订单有自己的聚合,因此要获取客户的订单信息,我必须调用 OrderRepository,这也会降低性能。

所以现在我想我只剩下两个选择:

  1. 向 CustomerRepository 添加一个额外的 Find 方法,该方法通过执行一个有效的查询返回这些摘要对象的列表。

  2. 创建一个专门构建的只读 CustomerInfoRepository,它只有 1 中描述的 find 方法。

但这两个感觉都像是我违背了 DDD 的原则。我的存储库继承自通用基础:Repository where T : IAggregateRoot。这些摘要信息对象不是聚合,并且与 T 的类型不同,因此#1 确实违背了设计。

也许对于#2,我会创建一个没有 IAggregateRoot 约束的抽象 SearchRepository ?

在我的领域里有很多类似的场景。

您将如何实现这个场景?

谢谢, Dave

更新

阅读 Theo 的答案后,我想我将采用选项 #2,并在我的基础设施中创建一个专门针对这些场景的 SearchRepository。然后,应用程序层(WCF 服务)可以调用这些存储库,这些存储库直接填充摘要 DTO,而不是将域实体映射到 DTO。

**** 更新 2 ****

虽然我一年多前就问过这个问题,但我想我只是补充一点,我已经发现了 CQRS,它旨在解决这个确切的问题。乌迪·达汉 (http://www.udidahan.com/) 和格雷格·杨 (http://codebetter.com/gregyoung/)已经写了很多关于它的文章。如果您正在使用 DDD 创建分布式应用程序,CQRS 适合您!

I have a question regarding DDD and the repository pattern.

Say I have a Customer repository for the Customer aggregate root. The Get & Find methods return the fully populated aggregate, which includes objects like Address, etc. All good. But when the user is searching for a customer in the UI, I just require a 'summary' of the aggregate - just a flat object with summarised information.

One way I could deal with this is to call the find method on the repository as normal, and then in the application layer, map each customer aggregate to a CustomerSearchResult / CustomerInfo DTO, and send them back to the client.

But my problem with this is performance; each Customer aggregate may require multiple queries to populate all of the associations. So if my search criteria matched 50 customers, that's quite a hit on the DB for potentially retrieving data I'm not even going to need.

The other issue is that I may wish to include summarised data about the customer that is outside of the Customer's aggregate root boundary, such as the date of the last order made for example. Order has it's own aggregate and therefore to get the customer's order information I would have to call the OrderRepository, also degrading performance.

So now I think I'm left with two options:

  1. Add an additional Find method to the CustomerRepository which returns a list of these summary objects by doing one efficient query.

  2. Create a purpose built readonly CustomerInfoRepository, that just has the find method described in 1.

But both of these feel like I'm going against the principles of DDD. My repositories inherit from a generic base: Repository where T : IAggregateRoot. These summary info object are not an aggregates, and are of a different type to T, so really #1 goes against the design.

Perhaps for #2 I would create an abstract SearchRepository without the IAggregateRoot constraint?

There are many similar scenarios in my domain.

How would you implement this scenario?

Thanks,
Dave

Update

After reading Theo's answer, I think I will go with option #2 and create a specialised SearchRepository within my infrastructure geared towards these scenarios. The application layer (WCF services) can then call these repositories that just populate the summary DTOs directly rather than mapping domain entities to DTOs.

**** Update 2 ****

Although I asked this over a year ago I thought I'd just add that I've since discovered CQRS which is aimed at solving this exact problem. Udi Dahan (http://www.udidahan.com/) and Greg Young (http://codebetter.com/gregyoung/) have written a lot about it. If you are creating a distributed application with DDD, CQRS is for you!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

︶ ̄淡然 2024-08-25 06:38:25

我认为您只想显示摘要信息。这些汇总信息不是领域模型的实体或值对象。它们只是信息,仅此而已。

这类似于显示报告信息。如果我处理这样的事情,我不会坚持纯粹的 DDD 方法。您建议的选项是可以的,因为它可以完成您的工作。 DDD 不应被视为教条。跳出框框思考。稍微放松一下DDD。

但请注意,您只是在模型之外创建信息值以用于显示目的。因此,如果用户选择一位信息来对其进行某些操作(在域模型中定义),您需要从信息值中提取标识符,并从存储库中提取实体/值对象/聚合。

我强烈推荐这个视频:Eric Evans:自从这本书以来我对 DDD 的了解。如果你读过他的书,你真的应该看整个视频。请密切关注 30:00 左右的时间,Eric Evans 本人在此谈论聚合并提到您当前遇到的问题。

I think that you only want to display summarized information. These bits of summarized information are no entities or value objects of the domain model. They are only information, nothing more.

It is something like showing reporting information. If I deal with such things, I would not stick to the pure DDD approach. Your suggested options are OK, because it's getting your job done. DDD should be not treated as dogma. Think outside the box. Loosen up a bit DDD.

But be aware that you are just creating informational values outside the model for displaying purpose. So if a user selects one bit of information to make some operation with it (which is defined in the domain model), you need to extract the identifier from the informational values and pull out the entity/value object/aggregate from a repository.

I strongly recommend this video: Eric Evans: What I've learned about DDD since the book. If you read his book, you really should see the whole video. Pay very close attention at about time 30:00 where Eric Evans himself talks about aggregates and refers to the problem you currently have.

流云如水 2024-08-25 06:38:25

我会:

  1. 返回一个不同的对象,它代表要显示的对象的视图,例如 CustomerInfo。
  2. 返回一个数据表。通常,通用容器是最简单、最好的方法。

如果您的通用基础存储库中的 T 是客户,那么我认为您错误地应用了聚合根的概念,尽管我不是严格的 福音传教士。我会为客户设计一个存储库,返回与客户逻辑上或舒适地分组的任何数据,包括数据表或作为客户数据视图的只读对象。

I would:

  1. Return a different object that represents a view of my object for display, e.g. CustomerInfo.
  2. Return a DataTable. Often a generic container is the easiest and best way to go.

If the T in your generic base repository is a Customer, then I think you are mis-applying the concept of aggregate roots, though I'm not a strict Evansangelist. I would design a repository for Customer that returned any data that logically or comfortably groups with Customer, including DataTables or read-only objects that are views of Customer data.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文