DDD:我真的需要加载聚合中的所有对象吗? (性能问题)

2024-03-24

在 DDD 中,存储库加载整个聚合 - 我们要么加载全部,要么不加载。这也意味着应该避免延迟加载。

我关心的是性能方面的问题。如果这导致将数千个对象加载到内存中怎么办?例如,聚合Customer一万回来Orders.

在这种情况下,是否意味着我需要重新设计和重新思考我的聚合? DDD 是否就这个问题提供建议?


看看这个有效的总体设计 http://dddcommunity.org/library/vernon_2011/弗农的三篇系列文章。我发现它们对于了解何时以及如何设计较小的聚合而不是大型集群聚合非常有用。

EDIT

我想举几个例子来改进我之前的答案,请随意分享您的想法。

首先,关于聚合的快速定义(摘自领域驱动设计的模式、原则和实践斯科特·米勒所著)

实体和值对象协作形成满足领域模型内的不变量的复杂关系。当处理对象的大型互连关联时,通常很难确保对域对象执行操作时的一致性和并发性。领域驱动设计具有聚合模式来确保一致性并定义对象图的事务并发边界。大型模型按不变量进行分割,并分组为实体和值对象的聚合,这些实体和值对象被视为概念整体。

让我们通过一个例子来看看实践中的定义。

简单的例子

第一个示例展示了定义聚合根如何帮助确保对域对象执行操作时的一致性。

鉴于下一个业务规则:

获胜的拍卖出价必须始终在拍卖结束之前进行。如果在拍卖结束后进行中标,则该域将处于无效状态,因为不变量已被破坏并且模型无法正确应用域规则。

这里有一个由拍卖和出价组成的聚合,其中拍卖是聚合根。

如果我们说 Bid 也是一个单独的聚合根,那么您将有一个BidsRepository,你可以轻松地做到:

var newBid = new Bid(money);
BidsRepository->save(auctionId, newBid);

并且您在未通过定义的业务规则的情况下保存了出价。但是,将拍卖作为唯一的聚合根,您将强制执行您的设计,因为您需要执行以下操作:

var newBid = new Bid(money);
auction.placeBid(newBid);
auctionRepository.save(auction);

因此,您可以检查方法内的不变量placeBid如果他们想进行新的出价,任何人都不能跳过它。

在这里很明显,出价的状态取决于拍卖的状态。

复杂的例子

回到与客户相关联的订单示例,看起来没有不变量使我们定义一个由客户及其所有订单组成的巨大聚合,我们可以通过标识符引用来保持两个实体之间的关系。通过这样做,我们可以避免在获取客户时加载所有订单,并减轻并发问题。

但是,假设现在业务定义了下一个不变量:

我们希望为客户提供一个口袋,以便他们可以充钱来购买产品。因此,如果客户现在想要购买产品,则需要有足够的资金才能购买。

这么说来,pocket 是 Customer Aggregate Root 中的一个 VO。现在看来,拥有两个独立的聚合根(一个用于客户,另一个用于订单)并不是满足新不变量的最佳选择,因为我们可以在不检查规则的情况下保存新订单。看来我们被迫将客户视为根本。这将影响我们的性能、可扩展性和并发问题等。

解决方案?最终一致性。如果我们允许客户购买产品怎么办?也就是说,拥有订单的聚合根,因此我们创建订单并保存它:

var newOrder = new Order(customerId, ...);
orderRepository.save(newOrder);

我们在创建订单时发布一个事件,然后异步检查客户是否有足够的资金:

class OrderWasCreatedListener:
    var customer = customerRepository.findOfId(event.customerId);
    var order = orderRepository.findOfId(event.orderId);
    customer.placeOrder(order); //Check business rules
    customerRepository.save(customer);

如果一切顺利,我们就满足了不变量,同时保持了我们一开始想要的设计,每个请求仅修改一个聚合根。否则,我们将向客户发送电子邮件,告知其资金不足的问题。我们可以通过添加她可以用当前预算购买的电子邮件替代选项来提前实现这一目标,并鼓励她自掏腰包。

考虑到UI可以帮助我们避免客户没有足够的钱付款,但我们不能盲目信任UI。

希望您发现这两个示例都很有用,如果您为暴露的场景找到更好的解决方案,请告诉我:-)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

DDD:我真的需要加载聚合中的所有对象吗? (性能问题) 的相关文章

  • 模型与服务解耦:如果我的模型需要服务怎么办?

    服务层应该位于模型层之上 因此 模型不应该调用服务 然而 我面临着我需要的情况 例如 interface Component getResult class Number implements Component private value
  • 使用服务的 DDD 实体

    我有一个应用程序 我试图使用至少一个名义上的 DDD 类型的域模型来构建 并且正在努力解决某个部分 我的实体有一些业务逻辑 这些逻辑使用我当前在某些域服务中拥有的一些财务计算和费率计算 以及我放入值对象中的一些常量值 我正在努力解决如何让实
  • ASP.NET MVC Web 应用程序中视图逻辑和域逻辑之间的混淆

    我对域 应用程序逻辑和用户界面逻辑感到困惑 为了说明我想要确定的内容 我将在下面描述一个虚构的程序以供说明 1 想象一个带有一组 3 个级联下拉菜单的小型应用程序 当您选择一个下拉列表时 它会触发 jQuery Ajax GET 最终到达
  • 恢复域对象的最佳方法

    这是一个如此简单而常见的场景 我想知道到目前为止我是如何做到的以及为什么现在遇到问题 我有这个对象 基础设施程序集的一部分 public class Queue public class QueueItem public QueueItem
  • 具有行为和 ORM 的丰富域模型

    观看 Jimmy Bogard 的 NDC12 演示 Crafting Wicked Domain Models 后 http ndcoslo oktaset com Agenda http ndcoslo oktaset com Agen
  • DDD:通过身份引用聚合根内的实体

    我一直在寻找正确的参考方式entities位于一个聚合根 当我们只得到他们的身份来自 URL 参数 我问了一个上一个问题 https stackoverflow com questions 7196820 update an entity
  • DDD建模,聚合根之间的交互

    Marked my aggregate roots with 1 2 3 Looks quite nice almost like grapes 我不喜欢的是一个标有红色箭头的实体 让我们想象一下 AR 1 是公司 AR 2 是办公室 AR
  • 领域驱动设计和聚合参考

    我正在设计领域模型 但有些东西似乎不太好 我从一个主要的聚合开始 它引用了其他聚合 而其他聚合也引用了更多聚合 我可以从主聚合开始遍历孔域模型 我看到的问题是我将在内存中保存聚合的所有实例 这是一个好的设计吗 我可以通过延迟加载解决内存问题
  • CQRS 对于我的域是否正确?

    我正在对一个档案进行建模 它是视频点播系统的一部分 将存档想象成 Windows 资源管理器 其中多个用户可以创建文件夹 上传视频 重组文件夹等 有业务规则 权限 确定是否允许用户执行任务 即重命名文件夹 移动文件夹 查看文件夹等 我已将每
  • 实现领域驱动设计的函数式方法

    我在使用 C 编写领域驱动应用程序方面拥有丰富的经验 我编写的应用程序越多 我就越发现我想要采用一种不太适合标准 C OO 技术的方法 我想编写尽可能多的纯函数 因为它们真的很容易测试 我想以更具声明性的方式编写我的业务逻辑 所以我一直在研
  • 首先是 DDD 数据库。如何处理聚合

    我正在尝试学习 DDD 的概念 我做了一个项目 我使用数据库优先方法 在基础设施中 我添加了一个 edmx 文件 我选择自动生成实体 现在在 域 中我正在尝试创建聚合 但在这里我遇到了一些问题 我正在尝试创建一个名为 User 的聚合 但
  • 有界上下文、子域和通用语言

    a 对于包含两个或多个子域的 BC 存在概念重叠的可能性 甚至更糟糕的是 相同的概念 由其中几个子域使用 可能会被每个子域以不同的方式解释 理解 无论如何 如果 BC 确实包含许多子域 它是否应该提供几种通用语言 每个子域一种 或者所有子域
  • 存储库本身通常不经过测试?

    抱歉 我对存储库模式 单元测试和 orm 工具还不熟悉 我一直在研究单元测试和存储库模式 并得出一些结论 我想知道我是否正确 存储库模式有助于在使用它的控制器中替换单元测试 例如 对吧 因为创建上下文 在 EF 中 或会话 在 NH 中 的
  • 领域驱动设计:处理原子操作和事务

    必须保证每个聚合内部的一致性 在存储库中执行此操作很容易 因为我始终可以使用数据库或框架中的事务 我对存储库之外发生的事情表示怀疑 一项服务可能需要使用多个聚合来处理请求 在服务处理过程中或在保留聚合时可能会出现问题 如果服务处理过程中出现
  • 领域模型可以知道存储库吗?

    可能对于某些域逻辑实现实体需要访问存储库以更新 删除自身或任何相关实体 这听起来对吗 不 不是 至少对于标有 的问题 领域驱动设计 标签 当然 Active Record 模式有权在某些系统中生存 并且有些人发现强耦合很有用 但在 DDD
  • 身份验证和用户任务

    我正在考虑开发一个具有明确定义域的系统 主要基于网络 域的一部分包括像这样的实体Diary Booking Customer etc 不过我创建了另一个名为User其目的仅用于身份验证和授权 污染Customer具有特定于身份验证的数据的实
  • 定时任务应该放在哪一层?

    我正在尝试使用分层架构来实现 DDD 应用程序 我有 基础设施层 实现应用程序的技术特定部分的层 领域层 包含领域模型的层 应用层 包含与领域模型交互的干扰的层 接口层 从外部接收事件的层 经典的 3 层 基础设施 架构非常清晰 但我的应用
  • 在域驱动设计中设置模型属性默认值的最佳实践?

    在 DDD 中为新实体设置默认属性的最佳方法是什么 另外 为复杂属性 例如集合 设置默认状态的最佳方法是什么 我的感觉是默认值应该在模型本身中 因为它们是业务规则的一种形式 默认情况下 我们希望 X 是 Y 和 Z 并且域代表业务 通过这种
  • NHibernate IQueryable 集合作为 root 的属性

    我有一个根对象 它有一个集合属性 例如 I have a Shelf object that has Books Now public class Shelf public ICollection
  • 服务层设计。将事物放入服务层的原因

    我有一些与设计相关的问题 should service layer interfaces居住在一个domain layer 例如user service 将代码部分移动到单独层的主要原因是什么 should service layer居住在

随机推荐