Почему мой TakeLimit не удостоен чести TableQuery?
Я хотел бы получить первые n строк из моей таблицы Azure с помощью простого TableQuery. Но с кодом ниже все строки выбираются независимо от моего лимита с Take.
Что я делаю неправильно?
int entryLimit = 5;
var table = GetFromHelperFunc();
TableQuery<MyEntity> query = new TableQuery<MyEntity>()
.Where(TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, "MyPK"))
.Take(entryLimit);
List<FeedEntry> entryList = new List<FeedEntry>();
TableQuerySegment<FeedEntry> currentSegment = null;
while (currentSegment == null || currentSegment.ContinuationToken != null)
{
currentSegment = table.ExecuteQuerySegmented(query, this.EntryResolver, currentSegment != null ? currentSegment.ContinuationToken : null);
entryList.AddRange(currentSegment.Results);
}
Trace.WriteLine(entryList.Count) // <-- Why does this exceed my limit?
2 ответа
Метод Take в SDK хранилища не работает, как в LINQ. Представьте, что вы делаете что-то вроде этого:
TableQuery<TableEntity> query = new TableQuery<TableEntity>()
.Where(TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, "temp"))
.Take(5);
var result = table.ExecuteQuery(query);
Когда вы начнете перебирать result
изначально вы получите только 5 предметов. Но внизу, если вы продолжаете перебирать result
, SDK будет продолжать запрашивать таблицу (и переходить к следующей "странице" из 5 пунктов).
Если в моей таблице 5000 элементов, этот код выведет все 5000 элементов (а под SDK будет выполнено 1000 запросов и получено 5 элементов на запрос):
TableQuery<TableEntity> query = new TableQuery<TableEntity>()
.Where(TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, "temp"))
.Take(5);
var result = table.ExecuteQuery(query);
foreach (var item in result)
{
Trace.WriteLine(item.RowKey);
}
Следующий код получит ровно 5 элементов в 1 запросе и остановится на этом:
TableQuery<TableEntity> query = new TableQuery<TableEntity>()
.Where(TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, "temp"))
.Take(5);
var result = table.ExecuteQuery(query);
int index = 0;
foreach (var item in result)
{
Console.WriteLine(item.RowKey);
index++;
if (index == 5)
break;
}
На самом деле, метод Take() устанавливает размер страницы или "счет" (свойство TakeCount в TableQuery). Но вы все равно должны прекратить повторение по времени, если вы хотите только 5 записей.
В вашем примере вы должны изменить цикл while, чтобы он останавливался при достижении TakeCount (который вы установили, вызывая Take):
while (entryList.Count < query.TakeCount && (currentSegment == null || currentSegment.ContinuationToken != null))
{
currentSegment = table.ExecuteQuerySegmented(query, currentSegment != null ? currentSegment.ContinuationToken : null);
entryList.AddRange(currentSegment.Results);
}
В AFAIK Storage Client Library 2.0 была ошибка в реализации Take. Это было исправлено в версии 2.0.4.
Прочитайте последние комментарии на http://blogs.msdn.com/b/windowsazurestorage/archive/2012/11/06/windows-azure-storage-client-library-2-0-tables-deep-dive.aspx