![](/img/trans.png)
[英]Using EventStore in a CQRS “architecture” makes unnecessary the use of a message bus?
[英]How to use eventstore in cqrs pattern
我正在研究CQRS
模式。 我創建了一個與此方法相關的項目,我可以在其中插入和檢索數據。 我開始知道有兩種不同的模型Write Model(Commands)和Read Model(Query)。 我只想知道我的寫模型方法是否正確。 當多個用戶進行相同的操作時,如何使用臨時數據庫進行事件采購。
Command.cs
public class Command : Message
{
}
public class Insert : Command
{
public readonly Guid Id;
public readonly string Name;
public Insert(Guid id, string name)
{
Id = id;
Name = name;
}
}
public class Update : Command
{
public readonly Guid Id;
public readonly string NewName;
public readonly int OriginalVersion;
public Update(Guid id, string newName)
{
Id = id;
NewName = newName;
}
}
public class Delete : Command
{
public Guid Id;
public readonly int OriginalVersion;
public Delete(Guid id)
{
Id = id;
}
}
Event.cs
public class Event:Message
{
public int Version;
}
public class Inserted : Event
{
public readonly Guid Id;
public readonly string Name;
public Inserted(Guid id, string name)
{
Id = id;
Name = name;
}
}
public class Updated : Event
{
public readonly Guid Id;
public readonly string NewName;
public readonly int OriginalVersion;
public Updated(Guid id, string newName)
{
Id = id;
NewName = newName;
}
}
public class Deleted : Event
{
public Guid Id;
public Deleted(Guid id)
{
Id = id;
}
}
EventStore.cs
public interface IEventStore
{
void SaveEvents(Guid aggregateId, IEnumerable<Event> events, int expectedVersion);
List<Event> GetEventsForAggregate(Guid aggregateId);
}
public class EventStore : IEventStore
{
private readonly IEventPublisher _publisher;
private struct EventDescriptor
{
public readonly Event EventData;
public readonly Guid Id;
public readonly int Version;
public EventDescriptor(Guid id, Event eventData, int version)
{
EventData = eventData;
Version = version;
Id = id;
}
}
public EventStore(IEventPublisher publisher)
{
_publisher = publisher;
}
private readonly Dictionary<Guid, List<EventDescriptor>> _current = new Dictionary<Guid, List<EventDescriptor>>();
public void SaveEvents(Guid aggregateId, IEnumerable<Event> events, int expectedVersion)
{
List<EventDescriptor> eventDescriptors;
if (!_current.TryGetValue(aggregateId, out eventDescriptors))
{
eventDescriptors = new List<EventDescriptor>();
_current.Add(aggregateId, eventDescriptors);
}
else if (eventDescriptors[eventDescriptors.Count - 1].Version != expectedVersion && expectedVersion != -1)
{
throw new ConcurrencyException();
}
var i = expectedVersion;
foreach (var @event in events)
{
i++;
@event.Version = i;
eventDescriptors.Add(new EventDescriptor(aggregateId, @event, i));
_publisher.Publish(@event);
}
}
public List<Event> GetEventsForAggregate(Guid aggregateId)
{
List<EventDescriptor> eventDescriptors;
if (!_current.TryGetValue(aggregateId, out eventDescriptors))
{
throw new AggregateNotFoundException();
}
return eventDescriptors.Select(desc => desc.EventData).ToList();
}
}
public class AggregateNotFoundException : Exception
{
}
public class ConcurrencyException : Exception
{
}
ReadModel.cs
public interface IReadModelFacade
{
IEnumerable<InventoryItemListDto> GetInventoryItems();
InventoryItemDetailsDto GetInventoryItemDetails(Guid id);
}
public class InventoryItemDetailsDto
{
public Guid Id;
public string Name;
public int CurrentCount;
public int Version;
public InventoryItemDetailsDto(Guid id, string name, int currentCount, int version)
{
Id = id;
Name = name;
CurrentCount = currentCount;
Version = version;
}
}
public class InventoryItemListDto
{
public Guid Id;
public string Name;
public InventoryItemListDto(Guid id, string name)
{
Id = id;
Name = name;
}
}
public class InventoryListView : Handles<Inserted>, Handles<Updated>
{
public void Handle(Inserted message)
{
BullShitDatabase.list.Add(new InventoryItemListDto(message.Id, message.Name));
}
public void Handle(Updated message)
{
var item = BullShitDatabase.list.Find(x => x.Id == message.Id);
item.Name = message.NewName;
}
}
public class InvenotryItemDetailView : Handles<Inserted>, Handles<Updated>
{
public void Handle(Inserted message)
{
BullShitDatabase.details.Add(message.Id, new InventoryItemDetailsDto(message.Id, message.Name, 0, 0));
}
public void Handle(Updated message)
{
InventoryItemDetailsDto d = GetDetailsItem(message.Id);
d.Name = message.NewName;
d.Version = message.Version;
}
private InventoryItemDetailsDto GetDetailsItem(Guid id)
{
InventoryItemDetailsDto d;
if (!BullShitDatabase.details.TryGetValue(id, out d))
{
throw new InvalidOperationException("did not find the original inventory this shouldnt happen");
}
return d;
}
}
public class ReadModelFacade : IReadModelFacade
{
public IEnumerable<InventoryItemListDto> GetInventoryItems()
{
return BullShitDatabase.list;
}
public InventoryItemDetailsDto GetInventoryItemDetails(Guid id)
{
return BullShitDatabase.details[id];
}
}
public static class BullShitDatabase
{
public static Dictionary<Guid, InventoryItemDetailsDto> details = new Dictionary<Guid, InventoryItemDetailsDto>();
public static List<InventoryItemListDto> list = new List<InventoryItemListDto>();
}
無論你是使用EventStore還是任何其他存儲機制,都應該對接口(契約)進行編碼。
但首先,你的命令IMO沒有正確定義,它們應該是不可變的對象,它們攜帶數據並表示域操作(CRUD與否),那么為什么你在命令中定義了方法呢?
將命令定義為類不是問題,最后需要一個,但為什么不將接口作為所有命令的基類型? (SOLID原則)
所有的類名(命令/事件)都必須有意義,即更新,刪除......真的不多說。
我也看不到你的服務層在哪里。 服務層應負責處理命令,那么您打算如何做到這一點?
貝婁,你有一個如何做到這一點的例子(有點抽象,但它給你一個想法):
// Message definitions
public interface IMessage
{
Guid ID {get; set;}
}
public interface IEvent : IMessage
{ }
public interface ICommand : IMessage
{ }
public class DeleteUserCommand : ICommand
{
public Guid ID {get; set;}
public Guid UserId {get; set;}
}
public class UserDeletedEvent : IEvent
{
public Guid ID {get; set;}
public Guid UserId {get; set;}
}
// Repository definitions
public interface IRepository
{ }
public interface IUserRepository : IRepository
{
void DeleteUser(Guid userId);
}
public UserRepository : IUserRepository
{
public void DeleteUser(Guid userId)
{}
}
// Service definitions
public interface IService
{ }
public class UserService : IService, IHandles<DeleteUserCommand>
{
public IUserRepository UserRepository {get; set;}
public void Handle(DeleteUserCommand deleteUserCommand)
{
UserRepository.DeleteUser(deleteUserCommand.Id)
//raise event
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.