最佳活动来源数据库策略



我想设置一个小型事件源库。我在网上读了一些教程,到目前为止一切都理解了。

唯一的问题是,在这些不同的教程中,有两种不同的数据库策略,但没有任何评论他们为什么使用他们使用的数据库策略。

所以,我想征求你的意见。重要的是,你为什么更喜欢你选择的解决方案。

  1. 解决方案是数据库结构,其中为每个事件创建一个表。

  2. 解决方案是使用数据库结构,只创建一个通用表,并将事件作为序列化字符串保存到一列中。

在这两种情况下,我都不确定他们是如何处理事件更改的,也许他们会创建一个全新的事件更改。

关于

我建立了自己的事件源库,并选择了选项2,原因如下。

  • 您按聚合id而不是事件类型查询事件流
  • 如果事件都在不同的表格中,那么按顺序再现事件将是一件痛苦的事情
  • 这会让升级活动有点痛苦

有一种说法是,您可以将事件存储在每个聚合上,但这取决于项目的要求。

我确实有一些关于如何使用事件流的帖子,你可能会觉得很有帮助。

  • 6代码气味与你的CQRS事件和如何避免它们

  • 聚合根-如何为CQRS和事件源构建一个

  • 如何在不破坏事件流的情况下升级CQRS事件

解决方案是使用数据库结构,只创建一个通用表,并将事件作为序列化字符串保存到一列中

这是迄今为止最好的方法,因为重放事件更简单。现在,我对活动来源的两点看法是:这是一个很好的模式,但你应该小心,因为并不是每件事都像看起来那么简单。在我正在研究的系统中,我们保存了每个聚合的事件流,但我们仍然有一组规范化的表,因为我们无法接受为了获得对象的最新状态,我们必须运行所有事件(快照有帮助,但不是完美的解决方案)。因此,是的,事件源是一种很好的模式,它为您提供了实体的完整版本控制和完整的审计日志,它应该仅用于此,而不是作为一组规范化表的替换,但这只是我的两分钱。

我认为最好的解决方案是使用#2。如果使用像mysql这样的事务数据库,甚至可以同时保存当前状态和相关事件。

我真的不喜欢并推荐解决方案#1

如果您对#1的关注是关于事件版本控制/升级;然后为每个新的更改声明一个新的类。不要太懒;或者痴迷于重复使用。让订阅者了解更改;给他们事件版本。

如果您对#1的关注是查询/解释事件;然后,您可以随时轻松地将事件推送到nosqldb或eventstore(从原始数据库)。

此外;我用于eventsourcinglib的模式是这样的:

public interface IUserCreated : IEventModel
{
}
public class UserCreatedV1 : IUserCreated
{
    public string Email { get; set; }
    public string Password { get; set; }
}
public class UserCreatedV2 : IUserCreated
{
    // Fullname added to user creation. Wrt issue: OA-143
    public string Email { get; set; }
    public string Password { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}
public class EventRecord<T> where T : IEventModel
{
    public string SessionId { get; set; } // Can be set in emitter.
    public string RequestId { get; set; } // Can be set in emitter.
    public DateTime CreatedDate { get; set; } // Can be set in emitter.
    public string EventName { get; set; } // Extract from class or interface name.
    public string EventVersion { get; set; } // Extract from class name
    public T EventModel { get; set; } // Can be set in emitter.
}
public interface IEventModel { }

所以;明确事件版本控制和升级;在域和代码库中。在部署新事件的来源之前,在订阅服务器中实现对新事件的处理。和如果不需要,则不允许直接使用来自外部订阅者的域事件;放一个集成层或类似的东西。

我希望我的想法对你有用。

  1. 有两个表:聚合表和事件表
  2. 基于您的用例:

    a。在聚合表上创建和注册,生成ID,版本=0和事件类型,并在事件表上创建事件;

    b。从聚合表中检索,按ID或事件类型检索事件,应用业务案例,然后更新聚合表(版本和事件类型),然后在事件表上创建事件。

尽管这种方法更新了聚合表上的一些字段,但它只将事件表保留为追加,并提高了性能,因为聚合表中有最新版本的聚合。

我会选择#2,如果你真的想通过事件类型进行有效的搜索,我只需要在该列上添加一个索引。

以下是访问本案例中涉及的主题数据的两种策略。1) 当前状态和2)事件排序。在当前状态下,我们处理事件,但只保留主题的最后状态。通过事件排序,我们保留事件,并通过每次需要状态时处理事件来重建当前状态。事件排序更可靠,因为我们可以跟踪导致当前状态的所有事件,但它肯定没有效率。保持中间状态(快照)而不仅仅是最后一个状态是常识,以避免一直重新处理所有事件。现在我们有了可靠性和性能。

在加密货币中,有事件排序和本地快照-名称中的本地是因为区块链是分布式的,数据是复制的。

最新更新