CQRS:在没有事件源的情况下更新读取模型
CQRS: Update Read-Model without Event Sourcing
我们已经构建了一个基于 CQRS 的系统,在域端使用关系数据库,在读取端使用 NoSQL 数据库。域端遵循 class 逻辑关系方法,而读取端是非规范化的。
数据复制和转换是使用命令处理程序发出的事件完成的。
我有两个关于读端同步的问题:
使用域端的关系数据完全重建读取模型的最佳方法是什么?
让我们假设读取模型不同步。
但即使它始终保持同步,也可能需要导入一个测试数据库
或者做一些批量操作。所以有人可能想要
从现有的写入模型到 运行 系统,而没有相应的同步读取模型。由于我们不使用事件溯源,因此没有
重播所有事件的方式。
我目前考虑 ReadModelBuilder
基本上做
SELECT * FROM 在每个 table 上并将每个实体转换为读取端
表示。但这引入了冗余。
ReadModelBuilder 需要知道转换是如何完成的。
通常进行读取端同步的事件处理程序也是如此
在命令处理程序执行一些写操作之后。
我考虑过放弃事件处理程序并用
每个 class 级别的同步机制。
例如。而不是 FooRenamedEventHandler
重命名 foo.name
,它将
调用 FooReadModelBuilder
重写完整的 Foo
实例。
但我认为这有缺点。 FooRenamedEventHandler 可以处理很多
在读取模型中冗余使用 foo.name
会更好。
更新:
另一种方法可能是让 ReadModelBuilder
通过将域实例分割成事件来创建读取模型实体,这将在顺序执行时构建完整的读取端实体。
例如:
Article
域实体有一个 Name
和一个 Price
。
为了构建读取端模型,ReadModelBuilder
可以检查域实体并发出 ArticleCreatedEvent
、ArticleRenamedEvent
和 ArticlePriceChangedEvent
。这样,转换逻辑将保留在事件处理程序中,但仍可从某种批量复制机制调用。
例如,ReadModelBuilders 可能如下所示:
_
interface IReadModelBuilder<TEntity>
{
//// Returns a sequence of events which replicate the read-model
//// when executed by the event handlers.
Event[] GetReplicationSequence(TEntity instance);
}
更新结束
_
- 您通常如何检测不同步的读取模型?是否有一般的最佳实践?
如果您不保留事件(即不使用 Event sourcing
),那么您将无法轻松重建 read-model
。您的 Rebuilder
必须以某种方式尝试对写入模型进行逆向工程并制造一些奇怪的事件,因为 write model
甚至无法包含所有信息,因为它不需要这些信息来完成他的工作。
所以,我的结论是,如果没有 event store
或至少没有 event log
,那么您将无法重建 read-model
。如果你有这样的真实来源,那么你可以重建它,甚至可以通过在某种持久性中使用所有已处理事件 ID 的列表来检测不同步的情况。
我们已经构建了一个基于 CQRS 的系统,在域端使用关系数据库,在读取端使用 NoSQL 数据库。域端遵循 class 逻辑关系方法,而读取端是非规范化的。 数据复制和转换是使用命令处理程序发出的事件完成的。
我有两个关于读端同步的问题:
使用域端的关系数据完全重建读取模型的最佳方法是什么?
让我们假设读取模型不同步。 但即使它始终保持同步,也可能需要导入一个测试数据库 或者做一些批量操作。所以有人可能想要 从现有的写入模型到 运行 系统,而没有相应的同步读取模型。由于我们不使用事件溯源,因此没有 重播所有事件的方式。
我目前考虑
ReadModelBuilder
基本上做 SELECT * FROM 在每个 table 上并将每个实体转换为读取端 表示。但这引入了冗余。 ReadModelBuilder 需要知道转换是如何完成的。 通常进行读取端同步的事件处理程序也是如此 在命令处理程序执行一些写操作之后。我考虑过放弃事件处理程序并用 每个 class 级别的同步机制。 例如。而不是
FooRenamedEventHandler
重命名foo.name
,它将 调用FooReadModelBuilder
重写完整的Foo
实例。 但我认为这有缺点。 FooRenamedEventHandler 可以处理很多 在读取模型中冗余使用foo.name
会更好。更新: 另一种方法可能是让
ReadModelBuilder
通过将域实例分割成事件来创建读取模型实体,这将在顺序执行时构建完整的读取端实体。 例如:Article
域实体有一个Name
和一个Price
。 为了构建读取端模型,ReadModelBuilder
可以检查域实体并发出ArticleCreatedEvent
、ArticleRenamedEvent
和ArticlePriceChangedEvent
。这样,转换逻辑将保留在事件处理程序中,但仍可从某种批量复制机制调用。例如,ReadModelBuilders 可能如下所示:
_
interface IReadModelBuilder<TEntity>
{
//// Returns a sequence of events which replicate the read-model
//// when executed by the event handlers.
Event[] GetReplicationSequence(TEntity instance);
}
更新结束
_
- 您通常如何检测不同步的读取模型?是否有一般的最佳实践?
如果您不保留事件(即不使用 Event sourcing
),那么您将无法轻松重建 read-model
。您的 Rebuilder
必须以某种方式尝试对写入模型进行逆向工程并制造一些奇怪的事件,因为 write model
甚至无法包含所有信息,因为它不需要这些信息来完成他的工作。
所以,我的结论是,如果没有 event store
或至少没有 event log
,那么您将无法重建 read-model
。如果你有这样的真实来源,那么你可以重建它,甚至可以通过在某种持久性中使用所有已处理事件 ID 的列表来检测不同步的情况。