If I have two aggregates
like this:
First Aggregate :
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 :
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:
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 detail
for every worktime
related to a
specific worktimeRegulation
. And can't update the number of workhours in worktime
if there's reference in shiftDetails
. The previous example shows that we
have two worktimes(winter,summer)
, So we have a shiftdetai
l for
winter
to stick with 8
workinghours and a shiftdetail
for
summer
to stick with 6
working 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?
Is it okay for non aggregate-root (ShiftDetail) to hold a reference for another non aggregate-root (WorkTime)?
No, unless they exist in the same Aggregate.
You may hold references only to other Aggregate root's ID.
You may hold a reference to the ID of a nested Entity from another Aggregate but you should note that this ID is opaque, you may not assume anything about how it is used internally by it's Aggregate root to find the nested Entity.
Now I feel that invariant of shift details controlled by non-aggregate root(worktime) How to force this invariant?
You can enforce an invariant in two ways:
Inside an Aggregate. This means that the Aggregate must me sufficient large, it must own all the state it needs to. This enforcement is strongly consistent.
Coordinated by a Saga/Process manager. This component react to changes inside possible multiple Aggregates and send commands to other Aggregates. A Saga is the opposite of an Aggregate. This enforcement is eventually consistent.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With