我们使用了基于CQRS的系统,域部分采用关系型数据库,读取部分采用NoSQL数据库,域部分采用传统的关系性方法,而读取部分则是非规范化的。数据复制和转换是通过命令处理器所发出的事件来完成的。
我有两个关于读取端同步的问题:
1.怎样使用域部分的关系数据完全重建读模型是最好的方法?
假设读模型不同步。但即使它总是同步的,我们也可能想要导入一个测试数据库或进行一些批量操作。因此,我们可能希望从一个现有的写模型运行系统,而没有相应的同步的读模型。由于我们不使用事件溯源,因此没有办法重播所有事件。
我目前在考虑一个ReadModelBuilder,它基本上对每个表执行SELECT * FROM,并将每个实体转换为读取端表示。但这会引入冗余。ReadModelBuilder需要知道如何进行转换。因此,事件处理程序也需要知道这一点,它们通常在命令处理程序执行一些写操作后进行读取端同步。
我想过放弃事件处理程序,用每个类级别的同步机制来代替它们。例如,FooRenamedEventHandler不再重命名foo.name,而是调用FooReadModelBuilder来重新编写整个Foo实例。但我认为这种方法有缺点。FooRenamedEventHandler可以更好地处理读模型中foo.name的冗余使用。
更新:另一种方法是让ReadModelBuilder通过将域实例分为事件来创建读取模型实体,当按顺序执行时,事件将构建完整的读取端实体。例如:
Article域实体有一个Name和一个Price。为了构建读取端模型,ReadModelBuilder可以检查域实体并发出ArticleCreatedEvent、ArticleRenamedEvent和ArticlePriceChangedEvent。这样,转换逻辑就会留在事件处理程序中,但仍然可以从某种批量复制机制中调用。
例如,ReadModelBuilders可能如下所示:
我有两个关于读取端同步的问题:
1.怎样使用域部分的关系数据完全重建读模型是最好的方法?
假设读模型不同步。但即使它总是同步的,我们也可能想要导入一个测试数据库或进行一些批量操作。因此,我们可能希望从一个现有的写模型运行系统,而没有相应的同步的读模型。由于我们不使用事件溯源,因此没有办法重播所有事件。
我目前在考虑一个ReadModelBuilder,它基本上对每个表执行SELECT * FROM,并将每个实体转换为读取端表示。但这会引入冗余。ReadModelBuilder需要知道如何进行转换。因此,事件处理程序也需要知道这一点,它们通常在命令处理程序执行一些写操作后进行读取端同步。
我想过放弃事件处理程序,用每个类级别的同步机制来代替它们。例如,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);
}
更新结束
_
- 你通常如何检测不同步的读模型?有通用的最佳实践吗?