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:我真的需要加载聚合中的所有对象吗? (性能问题) 的相关文章

  • 使用没有 ORM 的 SQL 的规范模式,以及存储库模式

    我一直在研究 martin fowler 的企业架构模式中存储库模式部分简要描述的规范模式 以及网络上的几个示例 然而 几乎所有的示例 描述都是通过利用 ORM 和 IsSatisfiedBy 等方法创建的 这些方法由规范对象执行 并且可能
  • 在使用 ASP.NET MVC 和 ORM 解决方案时,我们是否需要使用存储库模式?

    我有点好奇其他开发人员在使用 Entity Framework 或 NHibernate 在 ASP NET MVC 中进行编程时应用存储库模式的经验 在我看来 这种模式已经在 ORM 本身中实现了 DbContext and DbSet
  • 关于 C# 的 AOP 的建议 [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • DDD是否适合所有类型的应用?

    对于这里和其他论坛提出的很多问题 我看到的一个常见反应是 您不需要为此执行 DDD 它是一个简单的 CRUD 应用程序 DDD 是一种过度设计 嗯 我是 DDD 的新手 我觉得 DDD 中有很多元素具有普遍吸引力并且可以全面使用 无论您的应
  • 使用 JPA/Spring 的(通用)DDD 存储库的方法:它看起来有问题吗?

    我对 DDD 和 JPA 还很陌生 我正在使用 JPA 和 Spring 开发一个通用存储库 我真的很喜欢文章中介绍的方法DDD 通用存储库 http codebetter com blogs gregyoung archive 2009
  • 如何调整规范模式来评估对象的组合?

    我知道规范模式描述了如何使用类的层次结构来实现ISpecification
  • 应如何聚合公开子实体的信息?

    从这个问题跟进实体是否应该有方法 如果有 如何防止它们在聚合之外被调用 https stackoverflow com questions 51907447 should entity have methods and if so how
  • 使用服务的 DDD 实体

    我有一个应用程序 我试图使用至少一个名义上的 DDD 类型的域模型来构建 并且正在努力解决某个部分 我的实体有一些业务逻辑 这些逻辑使用我当前在某些域服务中拥有的一些财务计算和费率计算 以及我放入值对象中的一些常量值 我正在努力解决如何让实
  • CQRS、DDD同步报告数据库

    我们正在尝试 CQRS 和 DDD 以及事件溯源 假设我有一位客户更新了电子邮件地址 这会触发 CustomerUpdatesEmailAddress 事件 这会进入我的操作 写入数据库 并更新表 我们的系统设计为有一个运行的 ETL 流程
  • 领域驱动设计和 IoC/依赖注入

    我现在正在尝试应用我学到的有关 DDD 的知识 但我对域模型中的依赖关系流有点困惑 我的问题是 实体是否应该了解域中的工厂 存储库 服务 存储库应该了解域中的服务吗 另一件困扰我的事情是当我想向集合添加实体时如何处理集合 假设我正在开发一个
  • 具有行为和 ORM 的丰富域模型

    观看 Jimmy Bogard 的 NDC12 演示 Crafting Wicked Domain Models 后 http ndcoslo oktaset com Agenda http ndcoslo oktaset com Agen
  • DDD建模,聚合根之间的交互

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

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

    我在DDD中添加 Stateful Stateless WebService等是应用层 应用服务 吗 从下面的链接来看 这似乎是正确的 第二个问题 我创建了一个存储库类 所有涉及存储库的方法调用都应该包装在应用程序服务中吗 或者我可以直接在
  • 涵盖 .NET 中的 TDD、DDD 和设计模式的书籍

    我想要一本能够真正让我全面了解使用 C TDD ASP NET MVC DDD 和设计模式 例如存储库模式 的现代 ASP NET 开发的书 我非常擅长 C 和 ASP NET MVC 但想填补空白 如果您对涵盖这些主题的一两本书有很好的体
  • 在哪里检查用户电子邮件尚不存在?

    我有一个帐户对象 可以像这样创建用户 public class Account public ICollection
  • 除了“真实”对象之外,DDD 存储库还可以使用摘要对象吗?

    假设我正在创建一个存储库来存储数字电子书 如下面的界面所示 该存储库将存储书籍的实际文本以及标识书籍的元数据 标题 作者 出版商 ISBN 等 public interface IBookRepository void AddBook Bo
  • 领域驱动设计:处理原子操作和事务

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

    让我们考虑一下典型的Order and 订单项目例子 假如说订单项目是的一部分Order聚合 只能通过订单添加 所以 要添加一个新的订单项目 to an Order 我们必须通过存储库加载整个聚合 将新项目添加到Order对象并再次保留整个
  • 寻找领域事件的例子

    有谁知道在哪里可以找到域事件实现的示例代码 如乌迪 达汉 http www udidahan com in 领域事件 救赎 http www udidahan com 2009 06 14 domain events salvation 在

随机推荐