CQRS 中的事件版本控制

问题描述 投票:0回答:5

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

我一直在尝试找到一种在系统中引入命令/事件版本控制的方法。我已经阅读了 google/stackoverflow 等上的许多帖子,但我仍然看到实现它的代码示例。版本控制时是否应该遵循推荐的模式?如果有的话有什么例子/片段吗?

编辑:这就是我已经做到的程度

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

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

大家觉得这个做法怎么样?

下一个待办事项

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

谢谢

events domain-driven-design versioning cqrs
5个回答
8
投票

通常您只需要对事件进行版本控制,您可以忽略这些命令,因为您不将它们存储在事件存储中。

实现版本控制的方法很少。我的方法很简单:

[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; }
}

当您从事件存储中读取事件时,您需要处理从旧事件到新事件的转换。

另外,您需要注意,您永远不会删除任何旧的事件类,因此我将它们装饰为“已过时”,以让其他开发人员知道不要使用该事件。


5
投票

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


2
投票

我会谨慎混合事件和命令。他们有不同的目的并解决不同的问题。

为了更好地理解我的意思,可以这样想 命令更像是 RESTful API,客户端-服务器通信。 而事件溯源更多的是一种存储数据的方式。

两者都需要版本控制作为通过不变性提供向后兼容性的一种方式,但同样出于不同的原因。因此实现和例外是不同的。

我肯定会推荐一本书Greg Young 的《Event Versioning》,以深入了解事件源系统的版本控制..

我还尝试围绕事件和事件演变、版本控制和迁移收集一些想法。

有关命令的更多信息,请查看 CQRS 系列,特别是 CQRS via HTTP


1
投票

诚然,我没有机会尝试以下操作,但我想从第一天开始就进行版本控制:

由于完整的类型名称是相关的,我会选择命名空间。

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
投票

在考虑为什么需要按照问题中提出的方式进行事件版本控制,更具体地说,按照答案中建议的方式进行事件版本控制时,我完全没有理由?

我只能想到两个用例

1-当前使用的事件类已被弃用,不再需要。 然后可以随时在 git 中找到该类。那么为什么要通过保留死类来使活动代码变得复杂呢?

2- 业务需求发生了变化,现在您需要保留基本事件,但您还需要另一个具有一些参数差异的类似事件。 这可以通过多种方式解决,例如装饰器模式可以在很大程度上帮助处理此类变化 或者,新事件可能代表一个独特的领域概念,而不是试图将概念强行引入现有模型,最好以更语义的方式命名它并以这种方式使用它。

© www.soinside.com 2019 - 2024. All rights reserved.