使用领域事件更新数据库中的实体
Using Domain Events to Update Entity in Database
我有一个 PurchaseOrder 聚合根,它有两个方法 FinalizeOrder 和 CancellOrder,它们都记录事件:OrderFinaziled 和 OrderCancelled。我被困在建模订单存储库上,我可以使用存储库模式中的那些事件来更新数据库中的实体吗?我不会在每次更改后都保存整个聚合根,我只想保存更改的字段,我使用的是 SqlClient,没有 ORM。
我的聚合根基 class:
public class AggregateRootBase<TID> : EntityBase<TID>
{
public AggregateRootBase(TID id) : base(id)
{
}
private readonly List<IDomainEvent> recordedEvents = new List<IDomainEvent>();
public IEnumerable<IDomainEvent> GetEvents()
{
return recordedEvents;
}
public void MarkEventsAsProcessed()
{
recordedEvents.Clear();
}
protected void RecordEvent(IDomainEvent @event)
{
recordedEvents.Add(@event);
}
}
PurchaseOrder class(跳过大部分属性):
public class PurchaseOrder : AggregateRootBase<int>
{
public PurchaseOrder(int id) : base(id)
{
IsFinalized = false;
IsCancelled = false;
}
public bool IsFinalized { get; set; }
public bool IsCancelled { get; set; }
public void FinalizeOrder()
{
IsFinalized = true;
RecordEvent(new OrderFinalized(Id,IsFinalized));
}
public void CancellOrder()
{
IsCancelled = true;
RecordEvent(new OrderCancelled(Id,IsCancelled));
}
}
和存储库:
public class PurchaseOrderRepository
{
void Save(PurchaseOrder purchaseOrder)
{
var events = purchaseOrder.GetEvents();
foreach (var evt in events)
{
if(evt.GetType() == typeof(OrderFinalized))
// use event args and update field using SqlCommand
else if (evt.GetType() == typeof(OrderCancelled))
// use event args and Update field Using SqlCommand
}
}
}
我还有一个 EventDispatcher,它在 AggregateRoot 成功持久化后调度事件(电子邮件通知)。
如果您想使用域事件来保存您的更改,您正在谈论 投影 事件到您的聚合状态。有一些工具可以帮助解决这个问题。您尝试做的事情类似于模式匹配,这是大多数函数式语言的常用功能。为了让生活更轻松,您可能需要检查 Projac. We use it for projections and it works very nicely. It also has SQL Server specific implementation.
之类的内容
您可以在此处找到一个示例:
public class PortfolioProjection : SqlProjection
{
public PortfolioProjection()
{
When<PortfolioAdded>(@event =>
TSql.NonQueryStatement(
"INSERT INTO [Portfolio] (Id, Name) VALUES (@P1, @P2)",
new { P1 = TSql.Int(@event.Id), P2 = TSql.NVarChar(@event.Name, 40) }
));
When<PortfolioRemoved>(@event =>
TSql.NonQueryStatement(
"DELETE FROM [Portfolio] WHERE Id = @P1",
new { P1 = TSql.Int(@event.Id) }
));
When<PortfolioRenamed>(@event =>
TSql.NonQueryStatement(
"UPDATE [Portfolio] SET Name = @P2 WHERE Id = @P1",
new { P1 = TSql.Int(@event.Id), P2 = TSql.NVarChar(@event.Name, 40) }
));
}
}
然后你可以初始化投影仪实例:
_projector = new SqlProjector(
Resolve.WhenEqualToHandlerMessageType(new PortfolioProjection()),
new TransactionalSqlCommandExecutor(
new ConnectionStringSettings(
"projac",
@"Data Source=(localdb)\ProjectsV12;Initial Catalog=ProjacUsage;Integrated Security=SSPI;",
"System.Data.SqlClient"),
IsolationLevel.ReadCommitted));
然后是项目活动:
void Save(PurchaseOrder purchaseOrder) =>
_projector.Project(purchaseOrder.GetEvents());
您也可以检查事件溯源模式,尽管它增加了相当多的复杂性。
我有一个 PurchaseOrder 聚合根,它有两个方法 FinalizeOrder 和 CancellOrder,它们都记录事件:OrderFinaziled 和 OrderCancelled。我被困在建模订单存储库上,我可以使用存储库模式中的那些事件来更新数据库中的实体吗?我不会在每次更改后都保存整个聚合根,我只想保存更改的字段,我使用的是 SqlClient,没有 ORM。
我的聚合根基 class:
public class AggregateRootBase<TID> : EntityBase<TID>
{
public AggregateRootBase(TID id) : base(id)
{
}
private readonly List<IDomainEvent> recordedEvents = new List<IDomainEvent>();
public IEnumerable<IDomainEvent> GetEvents()
{
return recordedEvents;
}
public void MarkEventsAsProcessed()
{
recordedEvents.Clear();
}
protected void RecordEvent(IDomainEvent @event)
{
recordedEvents.Add(@event);
}
}
PurchaseOrder class(跳过大部分属性):
public class PurchaseOrder : AggregateRootBase<int>
{
public PurchaseOrder(int id) : base(id)
{
IsFinalized = false;
IsCancelled = false;
}
public bool IsFinalized { get; set; }
public bool IsCancelled { get; set; }
public void FinalizeOrder()
{
IsFinalized = true;
RecordEvent(new OrderFinalized(Id,IsFinalized));
}
public void CancellOrder()
{
IsCancelled = true;
RecordEvent(new OrderCancelled(Id,IsCancelled));
}
}
和存储库:
public class PurchaseOrderRepository
{
void Save(PurchaseOrder purchaseOrder)
{
var events = purchaseOrder.GetEvents();
foreach (var evt in events)
{
if(evt.GetType() == typeof(OrderFinalized))
// use event args and update field using SqlCommand
else if (evt.GetType() == typeof(OrderCancelled))
// use event args and Update field Using SqlCommand
}
}
}
我还有一个 EventDispatcher,它在 AggregateRoot 成功持久化后调度事件(电子邮件通知)。
如果您想使用域事件来保存您的更改,您正在谈论 投影 事件到您的聚合状态。有一些工具可以帮助解决这个问题。您尝试做的事情类似于模式匹配,这是大多数函数式语言的常用功能。为了让生活更轻松,您可能需要检查 Projac. We use it for projections and it works very nicely. It also has SQL Server specific implementation.
之类的内容您可以在此处找到一个示例:
public class PortfolioProjection : SqlProjection
{
public PortfolioProjection()
{
When<PortfolioAdded>(@event =>
TSql.NonQueryStatement(
"INSERT INTO [Portfolio] (Id, Name) VALUES (@P1, @P2)",
new { P1 = TSql.Int(@event.Id), P2 = TSql.NVarChar(@event.Name, 40) }
));
When<PortfolioRemoved>(@event =>
TSql.NonQueryStatement(
"DELETE FROM [Portfolio] WHERE Id = @P1",
new { P1 = TSql.Int(@event.Id) }
));
When<PortfolioRenamed>(@event =>
TSql.NonQueryStatement(
"UPDATE [Portfolio] SET Name = @P2 WHERE Id = @P1",
new { P1 = TSql.Int(@event.Id), P2 = TSql.NVarChar(@event.Name, 40) }
));
}
}
然后你可以初始化投影仪实例:
_projector = new SqlProjector(
Resolve.WhenEqualToHandlerMessageType(new PortfolioProjection()),
new TransactionalSqlCommandExecutor(
new ConnectionStringSettings(
"projac",
@"Data Source=(localdb)\ProjectsV12;Initial Catalog=ProjacUsage;Integrated Security=SSPI;",
"System.Data.SqlClient"),
IsolationLevel.ReadCommitted));
然后是项目活动:
void Save(PurchaseOrder purchaseOrder) =>
_projector.Project(purchaseOrder.GetEvents());
您也可以检查事件溯源模式,尽管它增加了相当多的复杂性。