如何跨 Azure 存储 table 中的多个分区键进行查询?
how to query across multiple partition keys in an azure storage table?
我有以下用例:
- 用户请求创建小部件。在我的存储 table.
的“请求”分区中创建了一条包含详细信息的新记录
- 请求完成后 - 原始请求将从“请求”分区中删除并在“已配置”分区中重新创建。
在查询小部件时 - 我需要同时搜索请求分区和配置分区。
从阅读文档来看,我似乎可以创建过滤器?但这似乎有很多开销,因为我知道我只会返回 1 条记录(希望如此,除非我有错误)。
但是看来我必须添加很多逻辑来处理分页。
到目前为止,这是我的出发点:
entity = tableClient.GetEntity<TableEntity>(
"requested",
requestId);
像这样:
//entity = tableClient.GetEntity<TableEntity>(
// "requested",
// requestId);
List<string> filters = new List<string>();
filters.Add($"PartitionKey eq '{"requested"}'");
filters.Add($"PartitionKey eq '{"provisioned"}'");
filters.Add($"RowKey eq '{requestId}'");
string filter = String.Join(" and ", filters);
//should only ever return one ... but ...
var entities = tableClient.QueryAsync<TableEntity>(filter);
await foreach (Page<TableEntity> page in entities.AsPages())
{
Console.WriteLine("This is a new page!");
foreach (TableEntity qEntity in page.Values)
{
Console.WriteLine($"i found this request: {qEntity.GetString("requestId")} with status: {"status"}");
}
}
此代码目前无法运行 - 需要对其进行调试。但我想我会看看是否有更简单的方法来做到这一点。
谢谢。
考虑到一个实体只会出现在一个分区中,您可以将代码更改为:
List<string> filters = new List<string>();
filters.Add($"(PartitionKey eq 'requested' and RowKey eq '{requestId}')");
filters.Add($"(PartitionKey eq 'provisioned' and RowKey eq '{requestId}')");
string filter = String.Join(" or ", filters);
//should only ever return one ... but ...
var entities = tableClient.QueryAsync<TableEntity>(filter);
await foreach (Page<TableEntity> page in entities.AsPages())
{
Console.WriteLine("This is a new page!");
foreach (TableEntity qEntity in page.Values)
{
Console.WriteLine($"i found this request: {qEntity.GetString("requestId")} with status: {"status"}");
}
}
我建议先写一个 TryGetEntityAsync
扩展方法:
public static async Task<Response<T>?> TryGetEntityAsync<T>(this TableClient tableClient, string partitionKey, string rowKey, IEnumerable<string>? select = default, CancellationToken cancellationToken = default) where T : class, ITableEntity, new()
{
try
{
return await tableClient.GetEntityAsync<T>(partitionKey, rowKey, select, cancellationToken);
}
catch (RequestFailedException ex) when (ex.Status == 404)
{
return null;
}
}
然后,你可以一次做一个两点查询:
var entity =
(await tableClient.TryGetEntityAsync<TableEntity>("requested", requestId)) ??
(await tableClient.TryGetEntityAsync<TableEntity>("provisioned", requestId));
或同时:
var requestedEntityTask = tableClient.TryGetEntityAsync<TableEntity>("requested", requestId);
var provisionedEntityTask = tableClient.TryGetEntityAsync<TableEntity>("provisioned", requestId);
var entities = await Task.WhenAll(requestedEntityTask, provisionedEntityTask);
var entity = entities[0] ?? entities[1];
我有以下用例:
- 用户请求创建小部件。在我的存储 table. 的“请求”分区中创建了一条包含详细信息的新记录
- 请求完成后 - 原始请求将从“请求”分区中删除并在“已配置”分区中重新创建。
在查询小部件时 - 我需要同时搜索请求分区和配置分区。 从阅读文档来看,我似乎可以创建过滤器?但这似乎有很多开销,因为我知道我只会返回 1 条记录(希望如此,除非我有错误)。 但是看来我必须添加很多逻辑来处理分页。
到目前为止,这是我的出发点:
entity = tableClient.GetEntity<TableEntity>(
"requested",
requestId);
像这样:
//entity = tableClient.GetEntity<TableEntity>(
// "requested",
// requestId);
List<string> filters = new List<string>();
filters.Add($"PartitionKey eq '{"requested"}'");
filters.Add($"PartitionKey eq '{"provisioned"}'");
filters.Add($"RowKey eq '{requestId}'");
string filter = String.Join(" and ", filters);
//should only ever return one ... but ...
var entities = tableClient.QueryAsync<TableEntity>(filter);
await foreach (Page<TableEntity> page in entities.AsPages())
{
Console.WriteLine("This is a new page!");
foreach (TableEntity qEntity in page.Values)
{
Console.WriteLine($"i found this request: {qEntity.GetString("requestId")} with status: {"status"}");
}
}
此代码目前无法运行 - 需要对其进行调试。但我想我会看看是否有更简单的方法来做到这一点。
谢谢。
考虑到一个实体只会出现在一个分区中,您可以将代码更改为:
List<string> filters = new List<string>();
filters.Add($"(PartitionKey eq 'requested' and RowKey eq '{requestId}')");
filters.Add($"(PartitionKey eq 'provisioned' and RowKey eq '{requestId}')");
string filter = String.Join(" or ", filters);
//should only ever return one ... but ...
var entities = tableClient.QueryAsync<TableEntity>(filter);
await foreach (Page<TableEntity> page in entities.AsPages())
{
Console.WriteLine("This is a new page!");
foreach (TableEntity qEntity in page.Values)
{
Console.WriteLine($"i found this request: {qEntity.GetString("requestId")} with status: {"status"}");
}
}
我建议先写一个 TryGetEntityAsync
扩展方法:
public static async Task<Response<T>?> TryGetEntityAsync<T>(this TableClient tableClient, string partitionKey, string rowKey, IEnumerable<string>? select = default, CancellationToken cancellationToken = default) where T : class, ITableEntity, new()
{
try
{
return await tableClient.GetEntityAsync<T>(partitionKey, rowKey, select, cancellationToken);
}
catch (RequestFailedException ex) when (ex.Status == 404)
{
return null;
}
}
然后,你可以一次做一个两点查询:
var entity =
(await tableClient.TryGetEntityAsync<TableEntity>("requested", requestId)) ??
(await tableClient.TryGetEntityAsync<TableEntity>("provisioned", requestId));
或同时:
var requestedEntityTask = tableClient.TryGetEntityAsync<TableEntity>("requested", requestId);
var provisionedEntityTask = tableClient.TryGetEntityAsync<TableEntity>("provisioned", requestId);
var entities = await Task.WhenAll(requestedEntityTask, provisionedEntityTask);
var entity = entities[0] ?? entities[1];