DDD:聚合根

2023-11-21

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

我有 3 个实体:计划、计划角色和计划培训。每个计划可以包含许多 PlannedRoles 和 PlannedTrainings。

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

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

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

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

还有另一个不变量,规定只有当计划处于某种状态时才可以更改。因此,我不应该能够将任何 PlannedRoles 或 PlannedTrainings 添加到不处于该状态的计划中。同样,我无法用第二种方法强制执行这个不变量。

任何建议将不胜感激。

干杯, 莫什


我在设计模型时遇到了类似的问题,并提出了这个问题,我认为这可能对您有帮助,特别是关于您的第一点。

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

在搜索方面,我不使用“模型”,而是有专门的搜索存储库返回“Summary”对象......即“PlanSummary”。这些只不过是信息对象(可以认为更像是报告)并且不用于事务意义上 - 我什至没有在我的模型类库中定义它们。通过创建这些专用存储库和类型,我可以实现高性能搜索查询,其中可以包含分组数据(例如 PlannedTraining 计数),而无需在内存中加载聚合的所有关联。一旦用户在 UI 中选择这些摘要对象之一,我就可以使用 ID 来获取实际的模型对象并执行事务操作并提交更改。

因此,对于您的情况,我将为所有三个实体提供这些专门的搜索存储库,当用户希望针对其中一个实体执行操作时,您始终会获取它所属的计划聚合。

这样,您就可以进行高性能搜索,同时仍然保持单个聚合具有所需的不变量。

编辑 - 示例:

好的,所以我猜实现是主观的,但这就是我在应用程序中处理它的方式,使用“TeamMember”聚合作为示例。用 C# 编写的示例。我有两个类库:

  • Model
  • 报告

模型库包含聚合类,并强制执行所有不变量,报告库包含这个简单的类:

public class TeamMemberSummary
{
    public string FirstName { get; set; }

    public string Surname { get; set; }

    public DateTime DateOfBirth { get; set; }

    public bool IsAvailable { get; set; }

    public string MainProductExpertise { get; set; }

    public int ExperienceRating { get; set; }
}

报告库还包含以下接口:

public interface ITeamMemberSummaryRepository : IReportRepository<TeamMemberSummary>
{

}

这是应用程序层(在我的例子中恰好是 WCF 服务)将使用的接口,并将通过我的 IoC 容器 (Unity) 解析实现。 IReportRepository 与基础 ReportRepositoryBase 一样,存在于 Infrastructure.Interface 库中。所以我的系统中有两种不同类型的存储库 - 聚合存储库和报告存储库......

然后在另一个库 Repositories.Sql 中,我有实现:

public class TeamMemberSummaryRepository : ITeamMemberSummaryRepository
{
    public IList<TeamMemberSummary> FindAll<TCriteria>(TCriteria criteria) where TCriteria : ICriteria
    {
        //Write SQL code here

        return new List<TeamMemberSummary>();
    }

    public void Initialise()
    {

    }
}

那么,在我的应用程序层:

    public IList<TeamMemberSummary> FindTeamMembers(TeamMemberCriteria criteria)
    {
        ITeamMemberSummaryRepository repository 
            = RepositoryFactory.GetRepository<ITeamMemberSummaryRepository>();

        return repository.FindAll(criteria);

    }

然后在客户端中,用户可以选择这些对象之一,并对应用程序层中的对象执行操作,例如:

    public void ChangeTeamMembersExperienceRating(Guid teamMemberID, int newExperienceRating)
    {
        ITeamMemberRepository repository
            = RepositoryFactory.GetRepository<ITeamMemberRepository>();

        using(IUnitOfWork unitOfWork = UnitOfWorkFactory.CreateUnitOfWork())
        {
            TeamMember teamMember = repository.GetByID(teamMemberID);

            teamMember.ChangeExperienceRating(newExperienceRating);

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

DDD:聚合根 的相关文章

随机推荐

  • 如何使用 C# 调用接收 Delphi 开放数组参数的函数?

    如何将 Delphi 代码转换为 C 代码 这需要一个array of Byte 但我不确定 C 的等价物是什么 我的尝试不起作用并引发 AccessViolationException 等异常 Delphi function SetLev
  • 为什么我没有看到 System.Delegate 上重载的 += 运算符?

    我看到相等比较运算符 and 超载于System Delegate and MulticastDelegate但不是 and 运营商 那么增量赋值和减量赋值运算符如何在委托实例上工作呢 C 编译器翻译 调用静态方法的运算符Delegate
  • 在facet_grid 的小平面之间绘制线条

    Intro 我想在多面 ggplot 之间画线 主要目标是将这些测量结果与我们要测试的线连接起来 所以基本上我想在 ggplot 箱线图 或任何类型的图 的内部和之间插入某种重要性条 Research ggsignif 我知道有ggsign
  • .NET - 字典锁定与 ConcurrentDictionary

    我找不到足够的信息ConcurrentDictionary类型 所以我想我应该在这里问一下 目前 我使用一个Dictionary保存由多个线程 来自线程池 因此没有确切数量的线程 不断访问的所有用户 并且它具有同步访问 最近发现 NET 4
  • PHP5 对象是通过引用传递的吗? [复制]

    这个问题在这里已经有答案了 我似乎无法获得任何关于此的一致信息 不同的来源似乎说了不同的事情 以及令人尊敬的 php net 本身 appears 不要明确说明这一点 尽管我必须承认 我只是快速浏览了一下 在我传递 重 对象的情况下 我需要
  • 删除 TabPage:处置或清除或两者兼而有之?

    我正在开发一个 Windows 窗体 它有一个名为 tabDocuments 的 TabControl 我遇到了这段代码 它从 TabControl 中删除所有页面 for int i tabDocuments TabPages Count
  • 如何在 IE8 中触发自定义 JavaScript 事件?

    我正在尝试在 IE8 上触发自定义事件并一起摆弄解决方案here and here 但我无法让它工作 我正在将 jquery mobile 与 requireJS 和谷歌分析一起使用 所以我正在跟踪 JQMpageshow事件 然而 由于
  • 如何设置服务来传递Google Sheet ID? AngularJS

    我正在使用 Angular 构建一个小部件 它接受用户给出的 Google Sheet Ids 并以漂亮的 json 格式发布输出 问题是我的代码什么也没做 控制台中没有错误 当我添加 ID 时没有任何反应 我想问题出在服务 js angu
  • Windows 8/8.1/10 中不显示名称为“卸载 <程序名称>”的快捷方式

    使用 MSI 安装程序 我们在 Windows 7 8 8 1 10 操作系统上创建应用程序快捷方式 除了应用程序快捷方式之外 我们还为程序创建卸载快捷方式 Win7 之前的快捷方式路径 ProgramsMenuFolder 公司名称 产品
  • 带有每个角色视图的客户端模板

    我一直在读关于AngularJS它看起来非常有前途 这是我想要弄清楚的唯一一件事 不是特定于框架的 但它对于客户端模板来说是通用的 假设您有一个具有多个角色的 Web 应用程序 每个角色可能包含附加功能 所以您不能为每个角色使用不同的模板
  • 如何在 HTML 中的新选项卡中打开链接?

    我正在开发一个 HTML 项目 但我不知道如何在没有 JavaScript 的情况下在新选项卡中打开链接 我已经知道了 a href http www WEBSITE NAME com a 在同一选项卡中打开链接 有什么想法如何让它在新的中
  • React.js 从子函数调用父函数

    我知道有几个类似的问题here and here但我很难理解今天对此的正确想法是什么 并将其推断到我的情况 我有一个简单的应用程序 ScoreBox 有一个 ScoreList 其中有很多分数 我想要一个 Score onClick 调用
  • R 安装包 RevoScaleR

    在尝试安装包 RevoScaleR 时 出现以下错误 我尝试过使用各种版本的 R 安装此软件包 但每次都会出现相同的错误 有谁知道为什么吗 install packages RevoScaleR install packages 中的警告
  • 在Python中检测Windows 8.1?

    我们有一个使用的脚本平台模块检测我们各种客户端的操作系统版本 查看platform py的源代码 我可以看到在Windows系统上 它使用sys getwindowsverion 不幸的是 在 Windows 8 1 系统上 该特定函数报告
  • Eclipse 中的 Python 文档

    有没有办法将标准Python文档集成到Eclipse中 因此 可以在 API 函数上按 F1 并在 Eclipse 的帮助视图中获取其描述 我使用 PyDev Thanks 我也遇到了同样的问题 所以我为此目的制作了一个 Eclipse 插
  • 如何保存并检查文件是否存在于作用域存储中?

    到目前为止 我检查文件是否存在 如果不存在 则将其保存到 Environment getExternalStoragePublicDirectory Environment DIRECTORY PICTURES 中的设备 但 Android
  • 在没有 DataBind 的情况下向 GridView 添加新行

    我有一个 GridView 它允许随时编辑每一列 每一行中的值 用户输入所有更改 单击 保存 一次 所有更改均已提交 用户还必须能够单击 新建 按钮 在 GridView 中显示一个新行 是的 它必须显示在实际的 GridView 中 输入
  • 当 C++ 标准提供将名称引入全局命名空间的 C 标头时,这是否包括重载?

    即将推出的 C 0x 标准的最终委员会草案表示 每个 C 标头 每个标头都有一个 name h 形式的名称 其行为就像 标准中的每个名称 库名称空间由相应的 cname 标头位于 全局命名空间范围 这是 未指定这些名称是否是 首先声明或定义
  • MYSQL根据列数据和表名连接表

    我想知道这是否可能 我想根据表1的数据连接2个表 示例表 1 具有列 food 其数据为 hotdog 我有一张桌子叫热狗 是否可以进行 JOIN 之类的操作 SELECT FROM table1 t join t food on id f
  • DDD:聚合根

    我需要帮助来找到我的聚合根和边界 我有 3 个实体 计划 计划角色和计划培训 每个计划可以包含许多 PlannedRoles 和 PlannedTrainings 解决方案 1 起初我认为 Plan 是聚合根 因为脱离 Plan 的上下文