Domain driven design 如何避免CQRS/DDD命令/事件中的大量数据加载?

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

我们有一个DDD AppDomain,包含研讨会、参与者和他们的膳食。我们每个研讨会最多有1000名参与者,每个参与者最多有50顿饭。我们决定,研讨会、参与者和膳食都是集合,以保持这些集合的小型化。 用户可以与所有参与者重新安排整个研讨会,也可以重新安排单个参与者。所以我们有命令“RescheduleSeminarCommand”和“RescheduleParticipantCommand”

重新安排研讨会时会出现问题:“RescheduleSMinarCommand”会导致“SeminarScheduleEvent”,这会导致每个参与者都执行“RescheduleParticipantCommand”。这意味着要从存储库中加载每个参与者,即1000个数据库请求。每一个“RescheduleParticipantCommand”都会导致一个“ParticipantRescheduleEvent”,它会触发“RescheduleMealsCommand”,为每个参与者加载膳食,这样就又有1000个数据库请求

我们如何减少数据库请求的数量

1) 我们考虑使用Seminand扩展“RescheduleParticipantCommand”和“RescheduleMealsCommand”,这样我们不仅可以加载一个参与者/餐,而且可以加载整个研讨会的所有参与者/餐

2) 另一种方法是创建额外的事件/命令,如“RescheduleParticipantsForMinarCommand”、“ParticipantsForMinarRescheduleEvent”和“RescheduleMealsForSeminarCommand”等

你认为什么更好?1) ,2)或是我们没有想到的其他东西


好的,我将给出我在第一次描述中遗漏的一些细节:

如果你有下列课程

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