Events 应用期间引发的CQRS事件
我在使用CQR建模和实现事件出席系统时遇到了一个问题。我的问题是子实体可以引发事件,但我不确定如何以及何时处理它 基本上,一个活动可以有参与者,他们以待定状态开始,可以接受或拒绝参加该活动。但是,他们可以更改出席人数,当这种情况发生时,我希望引发一个事件,以便事件处理程序可以处理(例如通知事件组织者) 我已经使用状态模式来管理与会者的状态,它取决于是否应该引发事件的当前状态。目前,此事件不会更改事件的状态。然而,在我看来,这个事件应该是事件流的一部分 我的问题是,在应用其中一个AttenderResponsed事件之前,我不知道是否会引发该事件,该事件会在当前状态下调用该方法。如果我在应用过程中引发事件,则在重新水化AR时会出现问题。我可以在应用过程中将此信息添加到事件中,并获得状态返回信息,但随后,事件变得易变 我的想法是,可能状态模式不适合作为事件生成的地方,或者状态模式不适合这里。我可以扩展state,让它有一个方法来确定某个状态更改是否会抛出一个事件,但这看起来很笨拙 最后,我的AR没有任何对eventBus的引用,因此我不能只是将事件扔到总线上,而不将其作为AR事件流的一部分。我认为AR对事件总线的引用开始违反SRP,但也许我在这方面错了 我已经加入了简化的代码来帮助我进行描述。有谁有一些有用的建议吗?谢谢,菲尔Events 应用期间引发的CQRS事件,events,domain-driven-design,cqrs,event-sourcing,state-pattern,Events,Domain Driven Design,Cqrs,Event Sourcing,State Pattern,我在使用CQR建模和实现事件出席系统时遇到了一个问题。我的问题是子实体可以引发事件,但我不确定如何以及何时处理它 基本上,一个活动可以有参与者,他们以待定状态开始,可以接受或拒绝参加该活动。但是,他们可以更改出席人数,当这种情况发生时,我希望引发一个事件,以便事件处理程序可以处理(例如通知事件组织者) 我已经使用状态模式来管理与会者的状态,它取决于是否应该引发事件的当前状态。目前,此事件不会更改事件的状态。然而,在我看来,这个事件应该是事件流的一部分 我的问题是,在应用其中一个AttenderR
公共类事件:EventSourceDaggerGetRoot
{
#区域字段
私有只读哈希集_attention=new HashSet();
私有Guid\u事件ID;
私有字符串\u标题;
#端区
#区域构造函数
[过时]
私人活动()
{
}
公共事件(LocalDate,字符串标题)
{
HandleEvent(创建的新事件(日期、标题、新GuidCombGenerator().generateWid());
}
公共事件(IEnumerable@events)
{
LoadsFromHistory(@events);
}
#端区
#区域属性和索引器
公共IReadOnlyCollection出席率
{
获取{return _attention.ToArray();}
}
公共Guid事件ID
{
获取{return\u eventID;}
专用设备
{
如果(_eventID==new Guid())_eventID=value;
else抛出新的FieldAccessException(“无法更改实体的ID”);
}
}
public LocalDate日期{get;private set;}
公共覆盖Guid ID
{
获取{return EventID;}
设置{EventID=value;}
}
公共字符串标题
{
获取{return\u title;}
专用设备
{
它(()=>值).IsNotNullOrWhiteSpace();
_标题=价值;
}
}
#端区
#区域方法
公共覆盖无效删除()
{
如果(!已删除)
HandleEvent(新事件已删除(事件ID));
}
public void UpdateEvent(LocalDate,字符串标题)
{
HandleEvent(新事件更新(日期、标题、事件ID));
}
public void AddAttendee(Guid成员ID)
{
Guard.That(()=>\u attention.IsTrue(set=>set.All(attendee=>attendee.MemberID!=MemberID),“与会者已经存在”);
HandleEvent(新添加的与会者(memberID、EventID));
}
public void DeleteAttendee(Guid成员ID)
{
Guard.That(()=>memberID).IsTrue(x=>Attention.Any(a=>attendee.memberID==memberID),“memberID不存在”);
HandleEvent(新与会者已删除(成员ID、事件ID));
}
内部void RespondIsComing(Guid成员ID)
{
Guard.That(()=>memberID).IsTrue(x=>Attention.Any(a=>attendee.memberID==memberID),“memberID不存在”);
HandleEvent(新与会者响应数据集(memberID、EventID));
}
内部void RespondNotComing(Guid成员ID)
{
Guard.That(()=>memberID).IsTrue(x=>Attention.Any(a=>attendee.memberID==memberID),“memberID不存在”);
HandleEvent(新与会者响应数据命名(memberID,EventID));
}
#端区
#区域事件处理程序
私有无效应用(EventCreated@event)
{
日期=@event.Date;
Title=@event.Title;
EventID=@event.EventID;
}
私有无效应用(EventDeleted@event)
{
删除=真;
}
私有无效应用(AttendenceAdded@event)
{
_添加(新与会者(@event.MemberID,@event.EventID));
}
私有无效应用(EventUpdated@event)
{
Title=@event.Title;
日期=@event.Date;
}
私有无效应用(AttenderRespondeDascoming@event)
{
var attendee=GetAttendee(@event.AttendeeID);
attendee.Accept();
}
私有无效应用(AttenderRespondeDasNotComming@event)
{
var attendee=GetAttendee(@event.AttendeeID);
attendee.Reject();
}
私有无效应用(Attendee已删除@事件)
{
_Attention.RemoveWhere(x=>x.AttendeeID==@event.AttendeeID);
}
受保护的覆盖无效ApplyEvent(IAggregateEvent@event)
{
应用((动态)@事件);
}
#端区
}
公开课参加者
{
#区域参与响应枚举
公共枚举参与响应
{
待定,
来,,
不来
}
#端区
#区域字段
私人IATTendenceResponseEstate(U attendState);
私有只读Guid\u事件ID;
私有只读Guid\u成员ID;
#端区
#区域构造函数
公众与会者
public class Event : EventSourcedAggregateRoot<Guid>
{
private readonly HashSet<AttendeeId> _attendance = new HashSet<Attendee>();
private EventId _eventID;
private string _title;
// generating AR ID should not be a responsibility of the AR
// All my IDs are generated by the client or the place where commands are created
// One thing about building CQRS systems is the you must trust the client. This is important. Google it.
public Event(EventId id, LocalDate date, string title, List<AttendeeId> attendees/* Can you create an event without attendees? */)
{
HandleEvent(new EventCreated(date, title, attendees, id));
}
This override reminds me of an active record pattern.
//public override void Delete()
public void Cancel()
{
if (!Deleted)
HandleEvent(new EventDeleted(EventID));
}
// May be you could split it to two events. The other one could be RescheduleEvent
// and all attendees will be notified. But changing the title could be just a typo.
public void UpdateEvent(LocalDate date, string title)
{
HandleEvent(new EventUpdated(date, title, EventID));
}
public void AddAttendee(AttendeeId memberID)
{
Guard.That(() => _attendance).IsTrue(set => set.All(attendee => attendee.MemberID != memberID), "Attendee already exists");
HandleEvent(new AttendeeAdded(memberID, EventID));
}
public void DeleteAttendee(AttendeeId memberID)
{
Guard.That(() => memberID).IsTrue(x => Attendance.Any(a => attendee.MemberID == memberID), "MemberID does not exist");
HandleEvent(new AttendeeDeleted(memberID, EventID));
}
internal void RespondIsComing(AttendeeId memberID)
{
Guard.That(() => memberID).IsTrue(x => Attendance.Any(a => attendee.MemberID == memberID), "MemberID does not exist");
HandleEvent(new AttendeeRespondedAsComing(memberID, EventID));
}
internal void RespondNotComing(AttendeeId memberID)
{
Guard.That(() => memberID).IsTrue(x => Attendance.Any(a => attendee.MemberID == memberID), "MemberID does not exist");
HandleEvent(new AttendeeRespondedAsNotComing(memberID, EventID));
}
private void Apply(EventCreated @event)
{
Date = @event.Date;
Title = @event.Title;
EventID = @event.EventID;
}
private void Apply(EventDeleted @event)
{
Deleted = true;
}
private void Apply(AttendeeAdded @event)
{
_attendance.Add(new Attendee(@event.MemberID, @event.EventID));
}
private void Apply(EventUpdated @event)
{
Title = @event.Title;
Date = @event.Date;
}
private void Apply(AttendeeRespondedAsComing @event)
{
var attendee = GetAttendee(@event.AttendeeID); // What this method does?
//attendee.Accept();
}
private void Apply(AttendeeRespondedAsNotComing @event)
{
var attendee = GetAttendee(@event.AttendeeID);// What this method does?
//attendee.Reject();
}
private void Apply(AttendeeDeleted @event)
{
_attendance.RemoveWhere(x => x.AttendeeID == @event.AttendeeID);
}
protected override void ApplyEvent(IAggregateEvent @event)
{
Apply((dynamic) @event);
}
}