If I have two aggregates like this:
First Aggregate :
- WorktimeRegulation (Root)
- Worktime
- RegulationEnrolment
Clarification with data:
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
Worktime :
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
Second Aggregate :
- Shift (Root)
- ShiftDetail
- ShiftEnrolment
Clarification with data:
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
ShiftDetail:
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
My questions here:
- Is it okay for non aggregate-root (
ShiftDetail) to hold a reference for another non aggregate-root (WorkTime)? The domain expert clarify that: To create a valid shift then we should have a
shift detailfor everyworktimerelated to a specificworktimeRegulation. And can't update the number of workhours inworktimeif there's reference inshiftDetails. The previous example shows that we havetwo worktimes(winter,summer), So we have ashiftdetail forwinterto stick with8workinghours and ashiftdetailforsummerto stick with6working hours. Now I feel that invariant of shift details controlled by non-aggregate root(worktime) How to force this invariant?According to the previous information do I make a mistake related to aggregates specifications?