问题标签 [aggregateroot]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
3 回答
1690 浏览

domain-driven-design - DDD:获取其他聚合的聚合根

在过去的两周里,我一直在研究 DDD,真正让我印象深刻的一件事是聚合根如何包含其他聚合根。聚合根从存储库中检索,但如果一个根包含另一个根,存储库是否有对另一个存储库的引用并要求它构建子根?

0 投票
3 回答
3332 浏览

domain-driven-design - DDD:聚合根

我需要帮助来找到我的聚合根和边界。

我有 3 个实体:Plan、PlannedRole 和 PlannedTraining。每个计划可以包括许多 PlannedRoles 和 PlannedTrainings。

解决方案 1:起初我认为 Plan 是聚合根,因为 PlannedRole 和 PlannedTraining 在计划的上下文之外没有意义。他们总是在一个计划之内。此外,我们有一条业务规则,规定每个计划最多可以有 3 个 PlannedRoles 和 5 个 PlannedTrainings。所以我想通过将计划指定为聚合根,我可以强制执行这个不变量。

但是,我们有一个搜索页面,用户可以在其中搜索计划。结果显示了计划本身的一些属性(并且没有任何 PlannedRoles 或 PlannedTrainings)。我想如果我必须加载整个聚合,它会产生很多开销。有近 3000 个计划,每个计划可能有几个孩子。将所有这些对象一起加载,然后在搜索页面中忽略 PlannedRoles 和 PlannedTrainings 对我来说没有意义。

解决方案 2:我刚刚意识到用户还需要 2 个搜索页面,他们可以在其中搜索计划角色或计划培训。这让我意识到他们正在尝试独立访问这些对象并且“脱离”Plan 的上下文。所以我认为我最初的设计是错误的,这就是我想出这个解决方案的原因。所以,我认为这里有 3 个聚合,每个实体 1 个。

这种方法使我能够独立搜索每个实体,还解决了解决方案 1 中的性能问题。但是,使用这种方法我无法强制执行我之前提到的不变量。

还有另一个不变量表明计划只有在它具有特定状态时才能更改。因此,我应该无法将任何 PlannedRoles 或 PlannedTrainings 添加到不在该状态的计划中。同样,我无法使用第二种方法强制执行此不变量。

任何建议将不胜感激。

干杯,莫什

0 投票
3 回答
2035 浏览

c# - ASP.NET MVC:什么机制返回 ViewModel 对象?

据我了解,域模型是仅描述数据(聚合根)的类。它们是 POCO,不引用外部库(没什么特别的)。

另一方面,视图模型是包含域模型对象以及所有接口特定对象(如SelectList. 一个 ViewModel 包括using System.Web.Mvc;.

存储库从数据库中提取数据并通过域模型对象将它们提供给我们。 什么机制或设备创建视图模型对象,从数据库中填充它们? 它会是一个可以访问数据库的工厂吗?您会将诸如 System.Web.Mvc 之类的视图特定类引入存储库吗?还有什么?

例如,如果您有一个城市下拉列表,您将在 View Model 对象的根目录中引用一个 SelectList 对象,就在您的 DomainModel 引用旁边:

城市应该来自数据库并采用选择列表对象的形式。希望您不要创建特殊的 Repository 方法来仅提取不同的城市,然后仅创建冗余的第二个 SelectList 对象,以便您拥有正确的数据类型。

0 投票
3 回答
1892 浏览

persistence - DDD:持久聚合

让我们考虑典型的OrderOrderItem示例。假设OrderItemOrder Aggregate 的一部分,它只能通过 Order 添加。因此,要向 Order 添加新的OrderItem 我们必须通过 Repository 加载整个 Aggregate,向Order对象添加新项目并再次持久化整个 Aggregate。

这似乎有很多开销。如果我们的Order有 10 个OrderItems怎么办?这样,仅仅添加一个新的OrderItem,我们不仅要读取 10 个OrderItems,而且我们还应该重新插入所有这 10 个OrderItems。(这是 Jimmy Nillson 在他的 DDD 书中采用的方法。每次他想要持久化一个 Aggregate 时,他都会清除所有子对象,然后再次重新插入它们。这可能会导致其他问题,因为孩子的 ID 是由于数据库中的 IDENTITY 列,每次都更改。)

我知道有些人可能会建议在聚合根中应用工作单元模式,以便跟踪已更改的内容并仅提交这些更改。但这违反了持久性无知 (PI) 原则,因为持久性逻辑正在泄漏到领域模型中。

有没有人考虑过这个?

莫什

0 投票
2 回答
330 浏览

nhibernate - NHibernate:具有根对象的根集合

我想跟踪不包含在任何元素中的根对象列表。我希望以下伪代码工作:

这应该会自动插入 item1 和 item2,删除 item3 和 item3 并更新 item5(即我不想分别为所有项目调用 sesssion.SaveOrUpdate() 。

是否可以定义与表无关的伪实体?例如,我想定义类收藏夹并映射它的 2 个集合属性,然后我想编写如下代码:

FavoriteColors 和 FavoriteMovies 是 Favorites 类的唯一属性,它们的类型为 IList 和 IList。我只想保留这两个集合属性,而不是收藏夹类。

实际上,我想要一个 IPersistentCollection 对象来跟踪不属于父实体并代表自身的添加和删除(与实体的集合属性发生的事情相同,仅在我的情况下我没有父实体)。如果集合属于一个实体,这非常有效,在这种情况下,我可以在两个会话之间添加和删除项目。

任何帮助深表感谢。

0 投票
2 回答
490 浏览

c# - 遍历聚合

对域驱动设计进行了一些阅读,似乎您应该通过从聚合根遍历来访问聚合中的所有实体。

但是,与此同时,您应该真正尝试封装您的数据,以便属性/字段受到保护或私有。

因此我的问题是:如果字段是受保护的/私有的,你应该如何遍历聚合?

我现在设置它的方式如下:我将域模型的所有属性标记为内部,并将“设置”方法标记为受保护。这样,至少模型之外的任何东西都不能访问属性,但是模型内的对象可以访问其他对象的属性,我仍然只允许从对象本身设置属性。

即使我已经这样做了,我仍然觉得这应该只适用于其他聚合实体的属性(我的意思是,客户的“名称”仍然是私有的,但他们的“订单”应该标记为内部以允许从客户 -> 订单 -> 等的遍历)

有人对此有任何指导吗?

编辑:

让我试着为这个问题举一个更具体的例子:我的对象图中有两个对象:Bookshelf 和 Book。为了这个例子,让我们说 Bookshelf 是聚合根,并且 Books 存储在书架上,因此只是聚合中的实体(Bookshelf 有书籍的集合)。

我想写一个方法来将一本新书添加到书架上。遵循 DDD 最佳实践,我相信我应该在 Bookshelf 类上编写一个方法,例如 AddBook(Book book)。

但是,如果有业务要求不能将同名书籍添加到书架上怎么办。我想要 Bookshelf.AddBook 方法中的一些逻辑来检查书籍的集合,以确保这本书不存在。

现在的问题是我不能这样做,因为我已经以一种很好的封装方式编写了 Book 对象,并且它的“Name”属性不可公开访问。

我知道这是一个相当人为的例子,但我希望它能更好地说明问题。我现在也意识到这不仅仅是 DDD 问题,而是现实中的 OO 封装问题。我敢肯定,必须有一种非常常见、简单的方法来解决我正在尝试做的事情,而且我在很大程度上想多了。

0 投票
2 回答
448 浏览

domain-driven-design - DDD:关于聚合边界的问题

我有一个复杂的场景,其中两个聚合边界相互矛盾。

我有 2 个实体:请求和任务。用户创建请求,然后他可以创建任务并将现有请求分配给任务。

请求和任务可以独立创建。换句话说,我在创建请求时不需要任务,反之亦然。

所以我假设我们在这里有 2 个不同的聚合:请求聚合和任务聚合,每个实体都是它自己聚合的根。

但是,我们有一个不变量违反了这个假设:您可以推迟或取消任务,这会导致分配给它的所有请求的状态相应地更新。

如果 Request 和 Mission 位于两个不同的聚合中,我该如何强制执行此约束?如果我将它们放在同一个聚合中,则无法分辨谁是聚合根,因为每个实体都可以独立创建。

有什么建议吗?

莫什

0 投票
2 回答
1216 浏览

asp.net-mvc - ASP.NET MVC/Entity Framework:通过聚合根存储库访问聚合对象

我正在使用 ASP.NET MVC 2 和实体框架构建我的第一个 Web 应用程序。我正在使用存储库模式。从我在 Stack Overflow 和其他网站上收集的信息来看,似乎共识是每个域模型对象有一个控制器,每个聚合根对象有一个存储库。

我的问题是我应该如何通过聚合根存储库访问非根聚合对象。在我正在处理的示例中,有一个 Customer 模型和一个 Boat 模型。船只能与客户的 FK 引用一起存在,并且船只需要在客户的上下文中被引用。这使我相信我有这两个对象的聚合,并且客户是根。

现在在我的 Boats 控制器中,我有一个 Edit 操作方法:

我的问题是如何在存储库中检索 Boat 对象?

我可以从客户存储库中引用 db.Boats 吗?它似乎是最干净的,但这意味着我将不得不更改我的 FakeCustomersRepository 以获得客户和船只列表。

通过 db.Customers 访问 Boat 对我来说似乎更合理,但是我无法弄清楚如何返回单个 Boat 对象而不在 LINQ 查询中重复自己,这真的不适合我。

我知道我还有很多东西要学,所以希望你能指出我正确的方向!

谢谢!

0 投票
1 回答
3028 浏览

domain-driven-design - DDD 建模,聚合根之间的交互

替代文字 用 1;2;3 标记了我的聚合根。看起来很不错——几乎像葡萄。

替代文字

我不喜欢的是一个标有红色箭头的实体。

让我们想象一下:

  • AR #1 是公司
  • AR #2 是办公室
  • AR #3 是员工
  • 标有红色箭头的实体被命名Country
    • 公司制定从哪些国家/地区雇用员工的规则(在雇用时,company.Countries.Contains(employee.Country)必须是真实的)

我以某种方式看到了域中这个相当不重要的部分(也许在这个示例中听起来不像),并且我想避免将 Country 提升为聚合根。

关于聚合根的词汇表说:

对内部成员的瞬态引用只能在单个操作中使用。

那么 - 引入诸如“EmployeeCountry”之类的内容,删除对公司 Country 的引用并检查 Employee country 在招聘操作中是否与任何公司国家匹配听起来合理吗?

还有其他想法吗?

我怎样才能让我的葡萄看起来像他们应该的样子?

0 投票
2 回答
1724 浏览

entity-framework - 如何使用实体框架对聚合进行建模?

虽然我处理域驱动设计 (DDD) 已经有一段时间了,但我对实体框架 (EF) 还是比较陌生,在 Visual Studio 中使用实体框架设计器时我想到的一个问题是如何聚合应在 EF 中表示/建模。

遵循 DDD 最佳实践,实体应仅引用同一聚合内的其他实体(或值对象),并且对其他实体的引用仅限于聚合的根实体(聚合根)。但是,我在 EF 中看不到任何这些概念(即,所有实体都被同等对待,因此对实体之间的引用没有任何限制)。

因此,我在问:我是否错过了 EF 中的某些内容,或者它是否完全不知道聚合、聚合根和实体之间的引用?如果是后者,那么在使用实体框架时如何对聚合进行建模?