Domain driven design 如何避免CQRS/DDD命令/事件中的大量数据加载?
我们有一个DDD AppDomain,包含研讨会、参与者和他们的膳食。我们每个研讨会最多有1000名参与者,每个参与者最多有50顿饭。我们决定,研讨会、参与者和膳食都是集合,以保持这些集合的小型化。 用户可以与所有参与者重新安排整个研讨会,也可以重新安排单个参与者。所以我们有命令“RescheduleSeminarCommand”和“RescheduleParticipantCommand” 重新安排研讨会时会出现问题:“RescheduleSMinarCommand”会导致“SeminarScheduleEvent”,这会导致每个参与者都执行“RescheduleParticipantCommand”。这意味着要从存储库中加载每个参与者,即1000个数据库请求。每一个“RescheduleParticipantCommand”都会导致一个“ParticipantRescheduleEvent”,它会触发“RescheduleMealsCommand”,为每个参与者加载膳食,这样就又有1000个数据库请求 我们如何减少数据库请求的数量 1) 我们考虑使用Seminand扩展“RescheduleParticipantCommand”和“RescheduleMealsCommand”,这样我们不仅可以加载一个参与者/餐,而且可以加载整个研讨会的所有参与者/餐 2) 另一种方法是创建额外的事件/命令,如“RescheduleParticipantsForMinarCommand”、“ParticipantsForMinarRescheduleEvent”和“RescheduleMealsForSeminarCommand”等 你认为什么更好?1) ,2)或是我们没有想到的其他东西Domain driven design 如何避免CQRS/DDD命令/事件中的大量数据加载?,domain-driven-design,cqrs,ddd-repositories,domain-model,Domain Driven Design,Cqrs,Ddd Repositories,Domain Model,我们有一个DDD AppDomain,包含研讨会、参与者和他们的膳食。我们每个研讨会最多有1000名参与者,每个参与者最多有50顿饭。我们决定,研讨会、参与者和膳食都是集合,以保持这些集合的小型化。 用户可以与所有参与者重新安排整个研讨会,也可以重新安排单个参与者。所以我们有命令“RescheduleSeminarCommand”和“RescheduleParticipantCommand” 重新安排研讨会时会出现问题:“RescheduleSMinarCommand”会导致“SeminarSc
好的,我将给出我在第一次描述中遗漏的一些细节: 如果你有下列课程
class Seminar
{
UUID SeminarId,
DateTime Begin,
DateTime End
}
// Arrival/Departure of a participant may differ
// from Begin/End of the seminar
class Participant
{
UUID ParticipantId
UUID SeminarId,
DateTime Arrival,
DateTime Departure
}
// We have one Meal-Object for breakfast, one for lunch and
// one for dinner (and additional for other meals) per day
// of the stay of the participant
class Meal
{
UUID MealId,
UUID ParticipantId,
DateTime Date,
MealType MealType
}
用户可以
- 使用“RescheduleParticipantCommand”更改单个参与者的到达/离开时间,这也会将他们的膳食更改为新的日期
- 使用“RescheduleSeminarCommand”更改研讨会的开始/结束,该命令将所有参与者的到达/离开更改为新的开始/结束,并相应地更改他们的膳食
- 如果你有一个研讨会,它是分为一些讲座,介绍等,还是一个研讨会相同的事情只是不同的人在不同的时间
- 你能先签一个人参加研讨会,然后决定这个人什么时候参加吗
- 这是一个分时段的研讨会(讲座、培训课程等)。同样的讲座将在不同的时间开始,给不同的人
- 参与者可以在不安排时间的情况下进行签名
- 当参与者签名时,我们需要根据偏好为他/她做一顿饭(例如,他/她可能是素食者或素食主义者)
- 调度将由系统用户在特定时间完成。他们在做计划时会记录参与者的信息。例如,我们可能希望在同一时间段或根据其他一些标准,有相同年龄的人
class Seminar {
UUID ID;
// other info for seminar like description, name etc.
}
class Participant {
UUID ID;
UUID SeminarID;
// other data for participant, name, age, meal preferences etc.
}
class TimeSlot {
Time StartTime;
TimeInterval Duration;
ReadonlyCollection<UUID> ParticipantIDs;
void AddParticipant(UUID participantID) { }
}
class SeminarSchedule {
UUID SeminarID;
Date Date;
Time StartTime;
TimeInterval Duration;
ReadOnlyCollection<TimeSlot> TimeSlots;
void ChangeDate(Date newDate) { }
void ChangeStartTime(Time startTime) { }
void ChangeDuration(TimeInterval duration) { }
void ScheduleParticipant(Participant p, Time timeSlotStartTime) { }
void RemoveParticipantFromSchedule(Participant p) { }
void RescheduleParticipant(Participant p, Time newTimeSlotStartTime) { }
}
课堂讨论会{
UUID-ID;
//研讨会的其他信息,如描述、姓名等。
}
课堂参与者{
UUID-ID;
UUID半干旱;
//参与者的其他数据、姓名、年龄、膳食偏好等。
}
类时隙{
时间开始时间;
时间间隔持续时间;
只读集合参与者;
void AddParticipant(UUID participantID){}
}
课程表{
UUID半干旱;
日期;
时间开始时间;
时间间隔持续时间;
只读收集时隙;
无效更改日期(日期新日期){}
无效更改开始时间(时间开始时间){
无效更改持续时间(时间间隔持续时间){}
无效ScheduleParticipant(Participant p,Time-timeSlotStartTime){}
void RemoveParticipantFromSchedule(参与者p){}
无效重新安排参与者(参与者p,时间newTimeSlotStartTime){}
}
这里我们有三个集合:研讨会
,参与者
和研讨会日程
如果您需要更改与研讨会
或参与者
相关的任何信息,您只需针对这些集合
另一方面,如果需要执行与计划相关的任何操作,则SeminarSchedule
聚合(作为计划的事务边界)将处理这些命令,以确保一致性。您还可以对计划实施并发控制。您可能不希望多人同时更改计划。例如,一个用户更改开始时间
,另一个用户更改持续时间
,或者让两个用户将同一参与者添加到计划中。您可以在SeminarSchedule
aggregate上使用
例如,更改子日程的开始时间
的持续时间
将影响所有时隙
如果您从研讨会
中删除参与者
,则您也必须将其从日程中删除。这可以通过最终的一致性和处理ParticipantRemoved
事件来实现,也可以使用
在对聚合进行建模时,我们需要考虑的另一件事是签署研讨会的逻辑是如何工作的
假设参与者在安排研讨会之前应该先签名。也许稍后将通过根据某些标准定义人员组来执行调度。上述模型将很好地工作。它将允许用户在研讨会
上签署参与者
。后来当
Update Seminar ( Begin , End) Values ( '06/02/2019' ,06/06/2019 ) where SeminarID = @SeminarID;
Update Participant ( Arrival , Departure ) Values ( '06/02/2019' ,06/06/2019 ) where SeminarId = @SeminarID