确保您不会使用 EventSourcing 两次添加同一个人数据
Making sure you don't add same person data twice using EventSourcing
我想知道您如何确保不会在 EventStore 中添加同一个人两次?
假设您在应用程序中添加了人员数据,但您希望确保不会在不同的流中两次添加相同的人名和生日。
你是问 ReadModels 还是在你的 Evenstore 里做?
I am wondering how you make sure you are not adding the same person twice in your EventStore?
您要解决的问题的一般形式是 set validation。
第 1 步是非常努力地推迟确保数据始终唯一的要求 - 如果它不必始终唯一,那么您可以使用检测和纠正方法。参见 Pat Helland 的 Memories, Guesses, and Apologies。粗略地翻译一下,你会尽你所能地利用你所拥有的信息,如果事实证明你必须恢复错误,请备份。
如果违反唯一性会让您面临无法接受table的风险(例如,因为复制违反了政府规定的隐私要求而被起诉破产),那么您必须工作。
要验证集合的唯一性,您需要锁定整个集合;这个锁在实现中可以是悲观的或乐观的。当整个集合存储在一个地方(也就是说,在一个锁下)时,这是相对简单的,但是当集合被分布式(也称为多个数据库)时,这就是一场噩梦。
如果您的集合是 聚合(这意味着为了更新目的,集合的成员被视为一个整体),那么 DDD 的机制很简单。将集合从 "repository" 加载到内存中,对集合进行更改,保留更改。
这种设计适用于每个聚合都有一个流的事件源——您可以通过锁定 "the" 流来防止竞争。
大多数人不想要这种设计,因为集合的成员很大,对于大多数数据,您只需要该数据的一小部分,所以 loading/storing 工作内存中的整个集合是浪费。
因此,他们所做的是将维护唯一性 属性 的责任从域模型转移到存储。 RDBMS 解决方案 非常擅长集合 。您定义维护 属性 的约束,数据库确保不允许任何违反约束的写入。
如果您的事件存储是关系数据库,您可以做同样的事情——事件流和 table 维护您的集合不变量在同一个事务中一起更新。
如果您的事件存储不是关系数据库?好吧,再一次,你必须看看钱——如果风险足够高,那么你 必须 丢弃不能让你解决问题的管道,而用能解决问题的管道。
在某些情况下,还有另一种方法:将需要唯一的信息编码到流标识符中。流来表示 "All users named Bob",然后您的域模型可以确保 Bob 流一次最多包含一个活跃用户。
然后你开始需要考虑 Bob 这个名字是不是 stable,当一个 unstable 名称更改。
人名是一个特别痛苦的问题,因为none of the things we believe about names are true。因此,您会遇到所有常见的唯一性问题,最多拨到 11 个。
如果你要验证这种事情,那么它应该在 IMO 本身的聚合中完成,你必须像你一样使用读取模型说。但是你最终将基础设施 code/dependencies 发送到你的 aggregates/passed 到你的方法中。
在这种情况下,我建议创建 Person.Id
、Person.Name
、Person.Birthday
的读取模型,然后创建一些服务而不是直接创建 Person
它使用读取模型 table 来查找一行是否存在,然后将聚合返回给您,或者创建一个新的聚合并将其返回。然后你根本不需要验证,只要所有的 Person-creation 都是通过这个服务完成的。
我想知道您如何确保不会在 EventStore 中添加同一个人两次?
假设您在应用程序中添加了人员数据,但您希望确保不会在不同的流中两次添加相同的人名和生日。
你是问 ReadModels 还是在你的 Evenstore 里做?
I am wondering how you make sure you are not adding the same person twice in your EventStore?
您要解决的问题的一般形式是 set validation。
第 1 步是非常努力地推迟确保数据始终唯一的要求 - 如果它不必始终唯一,那么您可以使用检测和纠正方法。参见 Pat Helland 的 Memories, Guesses, and Apologies。粗略地翻译一下,你会尽你所能地利用你所拥有的信息,如果事实证明你必须恢复错误,请备份。
如果违反唯一性会让您面临无法接受table的风险(例如,因为复制违反了政府规定的隐私要求而被起诉破产),那么您必须工作。
要验证集合的唯一性,您需要锁定整个集合;这个锁在实现中可以是悲观的或乐观的。当整个集合存储在一个地方(也就是说,在一个锁下)时,这是相对简单的,但是当集合被分布式(也称为多个数据库)时,这就是一场噩梦。
如果您的集合是 聚合(这意味着为了更新目的,集合的成员被视为一个整体),那么 DDD 的机制很简单。将集合从 "repository" 加载到内存中,对集合进行更改,保留更改。
这种设计适用于每个聚合都有一个流的事件源——您可以通过锁定 "the" 流来防止竞争。
大多数人不想要这种设计,因为集合的成员很大,对于大多数数据,您只需要该数据的一小部分,所以 loading/storing 工作内存中的整个集合是浪费。
因此,他们所做的是将维护唯一性 属性 的责任从域模型转移到存储。 RDBMS 解决方案 非常擅长集合 。您定义维护 属性 的约束,数据库确保不允许任何违反约束的写入。
如果您的事件存储是关系数据库,您可以做同样的事情——事件流和 table 维护您的集合不变量在同一个事务中一起更新。
如果您的事件存储不是关系数据库?好吧,再一次,你必须看看钱——如果风险足够高,那么你 必须 丢弃不能让你解决问题的管道,而用能解决问题的管道。
在某些情况下,还有另一种方法:将需要唯一的信息编码到流标识符中。流来表示 "All users named Bob",然后您的域模型可以确保 Bob 流一次最多包含一个活跃用户。
然后你开始需要考虑 Bob 这个名字是不是 stable,当一个 unstable 名称更改。
人名是一个特别痛苦的问题,因为none of the things we believe about names are true。因此,您会遇到所有常见的唯一性问题,最多拨到 11 个。
如果你要验证这种事情,那么它应该在 IMO 本身的聚合中完成,你必须像你一样使用读取模型说。但是你最终将基础设施 code/dependencies 发送到你的 aggregates/passed 到你的方法中。
在这种情况下,我建议创建 Person.Id
、Person.Name
、Person.Birthday
的读取模型,然后创建一些服务而不是直接创建 Person
它使用读取模型 table 来查找一行是否存在,然后将聚合返回给您,或者创建一个新的聚合并将其返回。然后你根本不需要验证,只要所有的 Person-creation 都是通过这个服务完成的。