【问题标题】:Event versioning in CQRSCQRS 中的事件版本控制
【发布时间】:2013-05-13 11:27:36
【问题描述】:

我们正处于开发周期 (asp.net mvc applciation) 的某个阶段,我们需要对现有命令和事件进行更改(例如添加/删除一些属性等)。

我一直在尝试找到一种在系统中引入命令/事件版本控制的方法。我已经阅读了很多关于 google/stackoverflow 等的帖子,但我仍然看到了一个实现它的代码示例。版本控制时是否应遵循推荐的模式。如果是,有任何示例/sn-ps?

编辑:这就是我在这方面取得的进展

  1. 我已经对我的事件进行了向后版本化,这样最新的事件将始终被称为相同,而过时的事件将添加一个后缀,如“_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; }
}

我仍然需要继续更改发布此事件的代码以包含新属性的值。

  1. 任何给定时间点,当我从事件存储中获取所有事件(例如,用于重播)时,它们在反序列化后(在本例中为 OrderSubmittedEvent)将始终具有相同类型,并且具有不属于旧属性的新属性使用其默认值填充的事件。

在重播我的事件时,我让我的事件通过 IEventUpgrader 这首先验证事件是否是可用的最新版本。由于类型始终是事件类型,因此此检查基于属性“LatestVersion”和“CurrentVersion”

大家如何看待这种方法?

下一个待办事项

  1. 如果事件是旧版本,则发布“UpdateMYEVENT”事件

谢谢

【问题讨论】:

  • 您使用的是事件溯源还是仅使用消息驱动的 CQRS?
  • @MikeSW - 只是消息驱动的 CQRS

标签: events domain-driven-design versioning 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

        【讨论】:

          猜你喜欢
          • 2013-02-16
          • 2010-10-01
          • 1970-01-01
          • 1970-01-01
          • 2017-11-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多