7

是否可以使用 Windows Azure 表存储服务进行条件插入?

基本上,我想做的是将新行/实体插入到表存储服务的分区中,当且仅当自上次查看以来该分区中没有任何更改时。

如果您想知道,我想到了事件溯源,但我认为这个问题比这更笼统。

基本上我想读取部分或整个分区并根据数据内容做出决定。为了确保自加载数据以来分区中没有任何变化,插入应该表现得像正常的乐观并发:只有在分区中没有任何变化时插入才应该成功 - 没有添加、更新或删除行。

通常在 REST 服务中,我希望使用 ETag 来控制并发,但据我所知,分区没有 ETag。

我能想出的最佳解决方案是为包含时间戳/ETag 的表中的每个分区维护一个单行/实体,然后将所有插入作为包含插入的批次的一部分以及对此的条件更新时间戳实体'。但是,这听起来有点麻烦和脆弱。

Azure 表存储服务可以做到这一点吗?

4

2 回答 2

3

一千英尺的景色

我可以和你分享一个小故事吗...

曾几何时,有人想为一个聚合(来自领域驱动设计的名声)保留事件以响应给定的命令。此人希望确保只创建一次聚合,并且可以检测到任何形式的乐观并发。

为了解决第一个问题——一个聚合只应该被创建一次——他做了一个插入到一个事务介质中,当检测到一个重复的聚合(或更准确地说是它的主键)时抛出。他插入的东西是作为主键的聚合标识符和变更集的唯一标识符。在处理命令时由聚合产生的事件集合,就是这里的变更集。如果有人或其他东西打败了他,他会认为已经创建的聚合并让它保持不变。变更集将预先存储在他选择的介质中。该媒体必须做出的唯一承诺是在被要求时按原样返回已存储的内容。存储变更集的任何失败都将被视为整个操作的失败。

为了解决第二个问题 - 在聚合的进一步生命周期中检测乐观并发 - 在编写了另一个变更集之后,当且仅当没有人在他背后更新聚合记录时,他才会更新事务介质中的聚合记录(即与他在执行命令之前最后一次阅读的内容相比)。如果发生这样的事情,交易媒介会通知他。这将导致他重新启动整个操作,重新读取聚合(或其变更集)以使命令这次成功。

当然,现在他解决了写作问题,随之而来的是阅读问题。如何能够读取构成其历史的聚合的所有变更集?毕竟,他只有最后提交的变更集与该事务介质中的聚合标识符相关联。因此他决定在每个变更集中嵌入一些元数据。在元数据中——作为变更集的一部分并不少见——将是上一个最后提交的变更集的标识符。通过这种方式,他可以“走”他的聚合变更集的路线,就像可以说的链表一样。

作为一个额外的好处,他还将命令消息标识符存储为变更集元数据的一部分。这样,在读取变更集时,他可以提前知道他要在聚合上执行的命令是否已经成为其历史的一部分。

一切都好,结局好...

PS
1.事务介质和变更集存储介质可以相同,
2.变更集标识符不能是命令标识符,
3.随意在故事中打孔:-),
4.虽然与 Azure Table 没有直接关系存储,我已经使用 AWS DynamoDB 和 AWS S3 成功实现了上述故事。

于 2012-01-31T19:09:39.237 回答
2

如何将每个事件存储在基于 AggregateId/AggregateVersion 创建的“PartitionKey/RowKey”中?其中 AggregateVersion 是基于聚合已有事件数的序列号。

这是非常确定的,因此在向聚合中添加新事件时,您将确保您使用的是它的最新版本,否则您将收到一条错误消息,指出该分区的行已经存在。此时,您可以放弃当前操作并重试,或者尝试确定是否可以合并操作,如果对聚合的新更新与您刚刚执行的操作不冲突。

于 2012-01-31T19:45:52.940 回答