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. 你不认为使用 _Version 在你的类名上使用包 V2、V3、VN 更好吗?【参考方案2】:

如果您只是添加和删除属性,则可能不需要版本事件;只需忽略已删除的序列化属性,并为您添加的属性使用合理的默认值。

【讨论】:

【参考方案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 中的事件版本控制的主要内容,如果未能解决你的问题,请参考以下文章

CQRS 事件溯源:验证用户名的唯一性

java泛型类,全网首发!

java写入文件怎么换行,经验分享

2021最新京东Java面试题目,2021大厂面试合集

java求职简历模板下载,社招面试心得

Java开发基础不牢?mysql创建联合索引语句