Event Sourcing 是将状态变更全部建模为不可变事件流,系统状态通过重放事件得到;事件须不可变、有序、持久化且带完整上下文;Apply 方法必须纯函数式;快照是必需的性能与正确性保障机制。
Event Sourcing 是什么,它不等于“加一堆 event”
Event Sourcing 的核心不是给类加 public event EventHandler,而是把状态变更**全部建模为不可变事件流**,系统当前状态由重放这些事件得到。你写的是“发生了什么”,而不是“现在是什么”。如果误以为只是用 event 关键字发通知,后续做快照、回溯、调试时会发现根本没法还原历史——因为那些事件没被持久化、没带完整上下文、没按时间顺序严格排序。
如何定义和存储事件(C# 实操要点)
事件是纯数据容器,必须满足:不可变、可序列化、带唯一 ID 和时间戳。不要在事件里存引用类型或业务逻辑。
- 用
record(C# 9+)定义事件,比如public record OrderPlaced(Guid OrderId, decimal Amount, DateTime OccurredAt); - 存储时必须保证顺序和幂等性:推荐用支持有序追加的存储,如 PostgreSQL 的表(带
sequence或timestamp排序字段)、SQL Server 的IDENTITY列,或专用事件存储如 EventStoreDB - 避免用 Entity Framework 直接映射事件——它默认按主键查,而事件查询主场景是“按聚合 ID + 版本号范围读”,EF 容易生成低效 SQL
如何从事件重建聚合根状态(Apply 方法陷阱)
聚合根的 Apply 方法负责将事件“应用”到内存状态,但常见错误是让它承担副作用(如发邮件、调外部 API),或者让 Apply 修改非当前聚合的状态。