2016-11-18 71 views
0

我发送某个服务的查询并取回结果。我想知道我过去是否已经得到相同的“答案”。所以,我打算使用Azure Table作为缓存机制。Azure存储表 - 插入批次行并检查它们是否存在

我做这个小POC:

TableBatchOperation batchOperation = new TableBatchOperation(); 
CachedUrl customer1 = new CachedUrl(Guid.Empty, "test1"); 
CachedUrl customer2 = new CachedUrl(Guid.Empty, "test2"); 
batchOperation.Insert(customer1); 
batchOperation.Insert(customer2); 
table.ExecuteBatch(batchOperation); 

当我运行在第一时间将此代码,它的正常工作。在这最后,我在桌上有两排。

问题出在第二次运行。当我执行此代码:

TableBatchOperation batchOperation = new TableBatchOperation(); 
CachedUrl customer1 = new CachedUrl(Guid.Empty, "test1"); 
CachedUrl customer2 = new CachedUrl(Guid.Empty, "test2"); 
CachedUrl customer3 = new CachedUrl(Guid.Empty, "test3"); 
batchOperation.Insert(customer1); 
batchOperation.Insert(customer2); 
batchOperation.Insert(customer3); 
table.ExecuteBatch(batchOperation); 

customer3附加)

期望得到是说一个消息:

  • customer1表 - 存在
  • customer2 - exists
  • customer3 - 添加

我其实得到的是这个异常(在ExecuteBatch()法):

索取资料请求ID:5116ee8a-0002-0024-7ac1-415787000000 RequestDate:星期五,2016年11月18日17:33:08 GMT状态消息:0:指定实体 已存在。 ErrorCode:EntityAlreadyExists

服务器发现#1实体存在,因此,跳过整个任务。

我该如何得到预期的答案?

天真的解决方案,是尝试添加所有N个项目,一个接一个。但是这个解决方案是最慢的一个(N个HTTP请求,而不是1个请求)。

回答

0

这是预期的行为。只要该批次中的任何实体出现故障,整批就会失败。

您可以使用的一种可能是使用InsertOrReplace方法而不是Insert。这将更新实体,如果它存在,否则插入实体。

documentation

添加一个TableOperation到插入 指定的实体到一个表,如果实体不存在的TableBatchOperation;如果 实体确实存在,则其内容将被提供的 实体替换。

+0

?通过这种方式,在执行命令后,我无法知道这些项目是新添加的还是刚刚被替换的... – No1Lives4Ever

+0

我不相信有方法可以判断实体是被替换还是只是被激活。也许表格存储不适合你正在尝试做的事情。你考虑过其他选择吗? –

2

Azure表存储批处理操作是原子操作,因此预计将在第一次失败操作时返回。批处理操作可能包含1000个操作,表服务在检测到第一个故障后继续执行所有操作的点并不多。

存储异常返回批处理中失败操作的实际索引以及与此相关的错误。

在失败操作的指数下方的例子是0和错误是EntityAlreadyExists:

:指定的实体已经存在。 ErrorCode:EntityAlreadyExists

您可以编写一个重试逻辑,捕获StorageException,解析错误,如果错误为EntityAlreadyExists,则从批处理中删除具有该索引的操作并重新提交批处理操作。

见Azure存储异常解析器我的NuGet实现从StorageException对象提取失败的操作和其他有用的信息的索引像HttpStatusCode你:https://www.nuget.org/packages/AzureStorageExceptionParser/

为了避免多次来回通话对于每个失败的操作,以下是一个替代解决方案,您可以探索:

每次向表中插入实体时,还会插入第二个实体,其中只包含行键的一个属性。让我们调用这个第二个实体RowKeyTracker实体。它将与原始实体具有相同的分区键,以便您可以执行批处理操作。它将有一个唯一的行键,以便查询它,并且它将具有一个属性,该属性是该分区的附加行键。如果RowKeyTracker实体已经存在,则每次插入新实体时,只需将新行键添加到该分区键的行键属性中,反之亦然;当删除实体时,也可以继续,并从RowKeyTracker中删除该行键实体。

因此,您可以使用此行密钥跟踪器实体,通过先查询它是否已经插入该分区的行密钥。

您可以使用如何`InsertOrReplace`可以解决我的问题,这种方法与第一种方法(试)相结合,有一个更强大的解决方案

相关问题