我们正处于开发周期(asp.net mvc 应用程序)的某个阶段,我们需要对现有命令和事件进行更改(例如添加/删除一些属性等)。
我一直在尝试找到一种在系统中引入命令/事件版本控制的方法。我已经阅读了 google/stackoverflow 等上的许多帖子,但我仍然看到实现它的代码示例。版本控制时是否应该遵循推荐的模式?如果有的话有什么例子/片段吗?
编辑:这就是我已经做到的程度
所以如果我有活动
public class OrderSubmittedEvent : IDomainEvent
{
public int OrderId { get; private set; }
public OrderSubmittedEvent(int orderId)
{
OrderId = orderId;
}
}
如果我必须添加一些属性,我会将上面的事件重命名为
public class OrderSubmittedEvent_V1 : IDomainEvent
{
public int OrderId { get; private set; }
public OrderSubmittedEvent_V1(int orderId)
{
OrderId = orderId;
}
}
并引入另一个与我的原始事件同名但添加了属性的事件,就像这样
public class OrderSubmittedEvent : IDomainEvent
{
public int OrderId { get; private set; }
public OrderSubmittedEvent(int version = 1, int orderId = 0, string customerName =
"Joe blogs", string address = "Earth")
{
OrderId = orderId;
CustomerName = customerName;
Address = address;
CurrentVersion = version;
}
public static int LatestVersion
{
get { return 2; }
}
public int CurrentVersion { get; set; }
public string CustomerName { get; set; }
public string Address { get; set; }
}
我仍然需要继续更改发布此事件的代码以包含新属性的值。
在重播我的事件时,我让我的事件通过 IEventUpgrader 这首先验证事件是否是可用的最新版本。由于类型始终是事件类型,因此此检查基于属性“LatestVersion”和“CurrentVersion”
大家觉得这个做法怎么样?
下一个待办事项
谢谢
通常您只需要对事件进行版本控制,您可以忽略这些命令,因为您不将它们存储在事件存储中。
实现版本控制的方法很少。我的方法很简单:
[Obsolete]
public class CompanyCreated
{
public Guid Id { get; set; }
public string Name { get; set; }
}
public class CompanyCreated_V2
{
public Guid Id { get; set; }
public string CompanyName { get; set; }
public string TaxNumber { get; set; }
}
当您从事件存储中读取事件时,您需要处理从旧事件到新事件的转换。
另外,您需要注意,您永远不会删除任何旧的事件类,因此我将它们装饰为“已过时”,以让其他开发人员知道不要使用该事件。
如果您只是添加和删除属性,则可能不需要对事件进行版本控制;只需忽略已删除的序列化属性,并为您添加的属性使用合理的默认值。
我会谨慎混合事件和命令。他们有不同的目的并解决不同的问题。
为了更好地理解我的意思,可以这样想 命令更像是 RESTful API,客户端-服务器通信。 而事件溯源更多的是一种存储数据的方式。
两者都需要版本控制作为通过不变性提供向后兼容性的一种方式,但同样出于不同的原因。因此实现和例外是不同的。
我肯定会推荐一本书Greg Young 的《Event Versioning》,以深入了解事件源系统的版本控制..
我还尝试围绕事件和事件演变、版本控制和迁移收集一些想法。
有关命令的更多信息,请查看 CQRS 系列,特别是 CQRS via HTTP。
诚然,我没有机会尝试以下操作,但我想从第一天开始就进行版本控制:
由于完整的类型名称是相关的,我会选择命名空间。
namespace Primary.Messages.V1
{
public class CompanyCreated
{
public Guid Id { get; set; }
public string Name { get; set; }
}
}
namespace Primary.Messages.V2
{
public class CompanyCreated
{
public Guid Id { get; set; }
public string Name { get; set; }
public string TaxNumber { get; set; }
}
}
这些可能位于不同的程序集中,您可以将较旧的程序集标记为已过时(如 Sarmaad 的建议)。但旧版本可能并不一定已经过时。
有什么想法吗?
在考虑为什么需要按照问题中提出的方式进行事件版本控制,更具体地说,按照答案中建议的方式进行事件版本控制时,我完全没有理由?
我只能想到两个用例
1-当前使用的事件类已被弃用,不再需要。 然后可以随时在 git 中找到该类。那么为什么要通过保留死类来使活动代码变得复杂呢?
2- 业务需求发生了变化,现在您需要保留基本事件,但您还需要另一个具有一些参数差异的类似事件。 这可以通过多种方式解决,例如装饰器模式可以在很大程度上帮助处理此类变化 或者,新事件可能代表一个独特的领域概念,而不是试图将概念强行引入现有模型,最好以更语义的方式命名它并以这种方式使用它。