CQRS 中的事件版本控制
Posted
技术标签:
【中文标题】CQRS 中的事件版本控制【英文标题】:Event versioning in CQRS 【发布时间】:2013-05-13 11:27:36 【问题描述】:我们正处于开发周期 (asp.net mvc applciation) 的某个阶段,我们需要对现有命令和事件进行更改(例如添加/删除一些属性等)。
我一直在尝试找到一种在系统中引入命令/事件版本控制的方法。我已经阅读了很多关于 google/*** 等的帖子,但我仍然看到了一个实现它的代码示例。版本控制时是否应遵循推荐的模式。如果是,有任何示例/sn-ps?
编辑:这就是我在这方面取得的进展
-
我已经对我的事件进行了向后版本化,这样最新的事件将始终被称为相同,而过时的事件将添加一个后缀,如“_V1”、“_V2”等。
如果我有活动
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;
我仍然需要继续更改发布此事件的代码以包含新属性的值。
-
任何给定时间点,当我从事件存储中获取所有事件(例如,用于重播)时,它们在反序列化后(在本例中为 OrderSubmittedEvent)将始终具有相同类型,并且具有不属于旧属性的新属性使用其默认值填充的事件。
在重播我的事件时,我让我的事件通过 IEventUpgrader 这首先验证事件是否是可用的最新版本。由于类型始终是事件类型,因此此检查基于属性“LatestVersion”和“CurrentVersion”
大家如何看待这种方法?
下一个待办事项
-
如果事件是旧版本,则发布“UpdateMYEVENT”事件
谢谢
【问题讨论】:
您使用的是事件溯源还是仅使用消息驱动的 CQRS? @MikeSW - 只是消息驱动的 CQRS 【参考方案1】:通常您只需要对事件进行版本控制,您可以忽略命令,因为您不将它们存储在事件存储中。
实现版本控制的方法很少..我的方法很简单:
[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;
当您从事件存储中读取事件时,您需要处理从旧事件到新事件的转换。
另外,您需要注意,您永远不会删除任何旧的事件类,因此我将它们装饰为过时的,以让其他开发人员知道不要使用该事件。
【讨论】:
@感谢您的回复。我已经用我的编辑更新了主要问题 @nesh_s 不确定为什么要“向后”版本,我认为这会增加混乱。此外,您的 IEventUpgrader 将始终知道源和目标类型。事件本身不应该知道它的版本号或持有任何基础设施信息。这是 IEventUpgrader 的角色,它更像是一种基础设施服务。从技术上讲,您提出的解决方案没有任何问题,只需记住维护、关注点分离和事件订阅者即可。 有趣。我想使用向后版本控制来确保每次添加新版本时都不必更改引用(使用事件的地方)。另外,当我的事件以版本号命名时,我的事件如何不知道它自己的版本号?你的意思是没有财产?这是我跟踪最新版本号的唯一方法。 @nesh_s 是的。我指的是版本属性。你不需要它。您的转换器应该通过 TYPE 明确知道如何将 Old_Class 转换为 New_Class 并且转换的逻辑应该存在于那里。我不知道你的转换器是什么样子,但看看 JOliver EventStore 的实现。它看起来像 IUpconvertEvents如果您只是添加和删除属性,则可能不需要版本事件;只需忽略已删除的序列化属性,并为您添加的属性使用合理的默认值。
【讨论】:
【参考方案3】:诚然,我还没有机会尝试以下方法,但我想从第一天开始就进行版本控制:
由于完整的类型名称是相关的,我会选择命名空间。
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 所建议的)。可能旧版本不一定已经过时了。
有什么想法吗?
【讨论】:
【参考方案4】:我完全没有理由考虑为什么需要事件版本控制问题的方式,更具体地说是答案中建议的方式?
我只能想到两个用例
1- 当前使用的事件类已弃用,不再需要。 然后可以随时在 git 中跟踪该类。那么,为什么要通过保留死类来麻烦和复杂化活动代码呢?
2- 业务需求发生了变化,现在您需要保留基本事件,但您还需要另一个类似的事件,但有一些参数差异。 这可以通过多种方式解决,例如装饰器模式可以在很大程度上帮助处理此类变化 或者,新事件可能代表一个独特的领域概念,与其试图将这个概念强加到现有模型中,不如更语义化地命名它并以这种方式使用它。
【讨论】:
【参考方案5】:我会谨慎混合事件和命令。他们有不同的目的,解决不同的问题。
为了更好地理解我的意思,请这样想 命令更像是 RESTful API,客户端-服务器通信。 而事件溯源更多的是一种存储数据的方式。
两者都需要版本控制作为通过不变性提供向后兼容性的一种方式,但再次出于不同的原因。因此实现和异常是不同的。
我肯定会推荐一本书 Event Versioning by Greg Young,以深入了解事件源系统的版本控制。
有关指挥的更多信息,请查看CQRS series,尤其是CQRS via HTTP。
【讨论】:
以上是关于CQRS 中的事件版本控制的主要内容,如果未能解决你的问题,请参考以下文章