非聚合根可以持有另一个非聚合根的引用吗?

Posted

技术标签:

【中文标题】非聚合根可以持有另一个非聚合根的引用吗?【英文标题】:Can non aggregate-root hold a reference for another non aggregate-root? 【发布时间】:2019-02-13 12:46:25 【问题描述】:

如果我有这样的two aggregates

第一个聚合:

WorktimeRegulation(根) 工作时间 法规注册

数据说明:

工作时间规定:

 public class WorkTimeRegulation : Entity<Guid>, IAggregateRoot
    
        private WorkTimeRegulation()//COMB
       : base(Provider.Sql.Create()) // required for EF
        
        
        private WorkTimeRegulation(Guid id) : base(id)
        
            _assignedWorkingTimes = new List<WorkingTime>();
            _enrolledParties = new List<RegulationEnrolment>();
        
        private readonly List<WorkingTime> _assignedWorkingTimes;
        private readonly List<RegulationEnrolment> _enrolledParties;
        public string Name  get; private set; 
        public byte NumberOfAvailableRotations  get; private set; 
        public bool IsActive  get; private set; 
        public virtual IEnumerable<WorkingTime> AssignedWorkingTimes  get => _assignedWorkingTimes; 
       public virtual IEnumerable<RegulationEnrolment> EnrolledParties  get => _enrolledParties; 
        //...
    

Id|    Name            |   NumberOfAvailableRotations|  IsActive 

 1|    General Rule    |          2                  |    true   

工作时间:

public class WorkTime : Entity<Guid>
    
        private WorkTime()
      : base(Provider.Sql.Create()) // required for EF
        
        
        private WorkTime(Guid id) : base(id)
        
            ActivatedWorkingTimes = new List<WorkingTimeActivation>();
        
        private ICollection<WorkingTimeActivation> _activatedWorkingTimes;

        public string Name  get; set; 
        public byte NumberOfHours  get; set; 
        public byte NumberOfShortDays  get; set; 
        public Guid WorkTimeRegulationId  get; private set; 
        public virtual ICollection<WorkingTimeActivation> ActivatedWorkingTimes  get => _activatedWorkingTimes; private set => _activatedWorkingTimes = value; 
        //....
   

Id|  Name   |   NumberOfHours| NumberOfShortDays |WorkTimeRegulationId 

1 | Winter  |     8          |    1              |    1
2 | Summer  |     6          |    0              |    1

第二个聚合:

Shift(根) 班次详情 班次注册

数据说明:

换档:

  public class Shift : Entity<Guid>, IAggregateRoot
    
        private readonly List<ShiftDetail> _assignedShiftDetails;
        private readonly List<ShiftEnrolment> _enrolledParties;


        public string Name  get; set; 
        public ShiftType ShiftType  get; set; 
        public int WorkTimeRegulationId  get; set; 
        public bool IsDefault  get; set; 
        public virtual WorkingTimeRegulation WorkTimeRegulation  get; set; 
        public virtual IEnumerable<ShiftDetail> AssignedShiftDetails  get => _assignedShiftDetails; 
        public virtual IEnumerable<ShiftEnrolment> EnrolledParties  get => _enrolledParties; 
        //...........
   

Id|  Name      |  ShiftType  |  WorkTimeRegulationId  | IsDefault 
1 | IT shift   |  Morning    |    1                   |  1 

换档细节:

  public class ShiftDetail : Entity<Guid>
    
        public Guid ShiftId  get; private set; 
        public Guid WorkTimeId  get; private set; 
        public DateTimeRange ShiftTimeRange  get; private set; 
        public TimeSpan GracePeriodStart  get; private set; 
        public TimeSpan GracePeriodEnd  get; private set; 
        public virtual WorkTime WorkTime  get; private set; 

        private ShiftDetail()
        : base(Provider.Sql.Create()) // required for EF
        
        
        //..........
   

ShiftId  WorkTimeId shift-start  shift-end   
  1          1        08:00        16:00
  1          2        08:00        14:00

我的问题在这里:

非聚合根 (ShiftDetail) 可以持有引用吗 对于另一个非聚合根 (WorkTime)?

领域专家澄清说:为了创建一个有效的转变,我们 应该有一个shift detail 对应于每个与 具体worktimeRegulation。如果shiftDetails 中有引用,则无法更新worktime 中的工作时间数。前面的例子表明我们 有two worktimes(winter,summer),所以我们有一个shiftdetail winter 坚持使用8 工作时间和shiftdetail summer 坚持6工作时间。现在我觉得非聚合根控制的班次细节不变量(worktime) 如何强制这个不变量?

根据前面的信息,我是否犯了与聚合规范相关的错误?

【问题讨论】:

【参考方案1】:

非聚合根 (ShiftDetail) 是否可以保存另一个非聚合根 (WorkTime) 的引用?

不,除非它们存在于同一个聚合中。

您只能持有对其他聚合根 ID 的引用。

您可能持有来自另一个聚合的嵌套实体 ID 的引用,但您应该注意,此 ID 是不透明的,您不能假设它的聚合根在内部如何使用它来查找嵌套实体。

现在我觉得非聚合根(worktime)控制的班次细节不变量如何强制这个不变量?

您可以通过两种方式强制执行不变量:

    在聚合内。这意味着聚合必须足够大,它必须拥有它需要的所有状态。这种强制执行非常一致。

    由 Saga/流程经理协调。该组件对可能的多个聚合内的更改做出反应,并将命令发送到其他聚合。 Saga 是 Aggregate 的对立面。这种执行最终是一致的。

【讨论】:

非常感谢您的回复,如果您能详细说明如何在我的具体情况下实现此功能,我将不胜感激。 @AnynameDonotcare 请详细说明您的不变量 首先对于与特定worktimeregulation相关的每个WorkTime实例我应该有一个ShiftDetail,在我的例子中我有两个worktimes(winter,summer)所以我应该有两个shiftdetails一个用于winter 和一个summer,其次ShiftTimeRange shiftdetails 在工作时间应该等于NumberOfHours 在我的例子中winter 工作时间NumberOfHours = 8 所以ShiftTimeRange = 08:00 to 16:00 - ->(16-8 = 8hours) @AnynameDonotcare 从我看到的情况来看,您可以在工厂中强制执行以 worktimeRegulation 作为输入并返回 ShiftTimeRange 的不变量 @AnynameDonotcare 这个工厂可能是返回 Shift 实例的 Shift 聚合上的静态方法

以上是关于非聚合根可以持有另一个非聚合根的引用吗?的主要内容,如果未能解决你的问题,请参考以下文章

基于ABP落地领域驱动设计-02.聚合和聚合根的最佳实践和原则

聚合根可以引用另一个根吗?

DDD中聚合聚合根的含义以及作用

存储库模式和聚合根模式和实体框架

基于ABP落地领域驱动设计-02.聚合和聚合根的最佳实践和原则

数据库和聚合根的存储库模式