我正在更新我的项目以使用
Azure.Data.Tables
12.6.1,但我不知道在哪里指定 Take
值来限制从查询返回的实体数量。
换句话说,我想做这样的事情:
var limit = 150;
var results = table.QueryAsync<T>(limit);
await foreach (var page in results.AsPages().ConfigureAwait(false)) {
// Regardless of how the server pages the results,
// only the top [limit] items are returned.
}
在旧 API 中,您可以在查询对象上设置
Take
属性。我该如何在新 API 中执行此操作?
正如 @Skin 指出的,当前的 SDK 并未公开
Take
的显式 API,但这是一个有意的决定,以确保开发人员更清楚从服务角度来看到底发生了什么。
旧的 SDK 支持完整的
IQueryable
API,这使得创建非常昂贵的查询变得很容易,这些查询在从服务获取整个表后执行过滤客户端。
虽然
Take
没有与其他 Linq 方法相同的问题,但该服务并不真正支持它。它只能限制分页结果的数量(服务上限为 1000)。
虽然我同意它不像 Take API 那么简单,但当前的 API 使得实现等效功能变得相当简单,同时不会隐藏您实际上可能从服务中获取超出 Take 限制的事实。
此示例演示了如何使用每页最大项目集来迭代页面。
这可能有点争议,但我将把它添加为答案......看起来它只是几周前作为功能请求提出的,现在已添加到待办事项中......
https://github.com/Azure/azure-sdk-for-net/issues/30985
您不是唯一有相同要求的人。
当限制低于 1000 Azure max 时,使用显式限制,当限制为 1000+ 时,计算有多少页并在达到计数时停止,然后修剪到精确计数。
当查询找到 5000 个且您想要的限制为 1001 时,最大开销将为 999,因为您将下载 2000 个项目并截断 999。当您的限制为 < 1000 you pull only 1 page with exact count of items (no ovearhaed).
理论上你可以进行复杂的 maxPerPage 计算,但这没有意义,HTTP 在延迟方面的成本更高,尤其是在移动设备上,因此最好少发出最大可能页面的请求,而不是更多较小页面的请求。
public async Task<IEnumerable<T>> QueryAsyncLimit<T>(string tableName, string filter, IEnumerable<string> select, int limit) where T : class, ITableEntity, new()
{
var tableClient = ...;
var entities = new List<T>();
var maxPerPage = limit < 1000 ? limit : 1000; // Azure page default is 1000 and it's max
var pages = tableClient.QueryAsync<T>(filter, maxPerPage, select).AsPages();
var currentPage = 1;
await foreach (var page in pages)
{
entities.AddRange(page.Values);
if (currentPage == GetPageCount(limit))
break; //stop "downloading" pages
currentPage++;
}
return entities.Take(limit); //cut off the excess when more than 1 page
}
private int GetPageCount(int limit)
{
int pageSize = 1000; // Azure page default is 1000 and it's max
int pageCount = (int)Math.Ceiling((double)limit / pageSize);
return pageCount;
}