2010-10-11 2 views
0

Я пытаюсь получить некоторые записи из хранилища таблиц Azure, используя пейджинг с токеном продолжения.Выражение не поддерживается при доступе к таблицам Azure

У меня есть следующий код:

public Stories SelectStory(DateTime start, DateTime end, string searchGuid) 
{ 
    long startTicks = DateTime.MaxValue.Ticks - start.ToUniversalTime().Ticks; 
    long endTicks = DateTime.MaxValue.Ticks - end.ToUniversalTime().Ticks; 

    var stories = _ServiceContext.CreateQuery<Story>("Story").Where(s => Convert.ToInt64(s.RowKey.Substring(0, s.PartitionKey.IndexOf("_"))) > startTicks 
     && Convert.ToInt64(s.RowKey.Substring(0, s.PartitionKey.IndexOf("_"))) < endTicks 
     && s.RowKey == "story_" + searchGuid).Take(50); 
    var query = stories as DataServiceQuery<Story>; 
    var results = query.Execute(); 
    var response = results as QueryOperationResponse; 

    Stories temp = new Stories(); 
    if(response.Headers.ContainsKey("x-ms-continuation-NextRowKey")) 
    { 
    temp.NextPartitionKey = response.Headers["x-ms-continuation-NextPartitionKey"]; 
    if (response.Headers.ContainsKey("x-ms-continuation-NextRowKey")) 
    { 
     temp.NextRowKey = response.Headers["x-ms-continuation-NextRowKey"]; 
    } 
    } 
    temp.List = results.ToList(); 

    return temp; 
} 

Но я получаю следующее сообщение об ошибке:

The expression (((ToInt64([10007].RowKey.Substring(0, [10007].PartitionKey.IndexOf("_"))) > 2521167043199999999) And (ToInt64([10007].RowKey.Substring(0, [10007].PartitionKey.IndexOf("_"))) < 2521154083199999999)) And ([10007].RowKey == "story_9")) is not supported. 

я не уверен, почему выражение не допускается. У кого-нибудь есть идеи, как я могу изменить его, чтобы заставить его работать?

Спасибо!

Edit: новый код (без ошибок, но данные не получает выбрано - даже если я знаю, что существует):

public Stories SelectStory(DateTime start, DateTime end, string searchGuid) 
    { 
     long startTicks = DateTime.MaxValue.Ticks - start.ToUniversalTime().Ticks; 
     long endTicks = DateTime.MaxValue.Ticks - end.ToUniversalTime().Ticks; 

     var strStart = string.Format("{0:10}_{1}", DateTime.MaxValue.Ticks - startTicks, "00000000-0000-0000-0000-000000000000"); 
     var strEnd = string.Format("{0:10}_{1}", DateTime.MaxValue.Ticks - endTicks, "00000000-0000-0000-0000-000000000000"); 

     var stories = _ServiceContext.CreateQuery<Story>("Story").Where(
         s => s.RowKey.CompareTo(strStart) < 0 
          && s.RowKey.CompareTo(strEnd) > 0 
          //s.RowKey.CompareTo(startTicks.ToString() + "_") > 0 
        //&& s.RowKey.CompareTo(endTicks.ToString() + "_00000000-0000-0000-0000-000000000000") > 0 
        && s.PartitionKey == ("story_" + searchGuid) 
        ).Take(50); 
     var query = stories as DataServiceQuery<Story>; 
     var results = query.Execute(); 
     var response = results as QueryOperationResponse; 

     Stories temp = new Stories(); 
     if(response.Headers.ContainsKey("x-ms-continuation-NextRowKey")) 
     { 
      temp.NextPartitionKey = response.Headers["x-ms-continuation-NextPartitionKey"]; 
      if (response.Headers.ContainsKey("x-ms-continuation-NextRowKey")) 
      { 
       temp.NextRowKey = response.Headers["x-ms-continuation-NextRowKey"]; 
      } 
     } 
     temp.List = results.ToList(); 

     return temp; 
    } 

ответ

1

ОК, я думаю, что есть несколько вещей, здесь происходит. Я думаю, что есть логический недостаток. не

Convert.ToInt64(s.RowKey.Substring(0, s.PartitionKey.IndexOf("_"))) 

Должно быть

Convert.ToInt64(s.PartitionKey.Substring(0, s.PartitionKey.IndexOf("_"))) 

Во-вторых вы должны быть очень осторожны, о том, какие функции поддерживаются лазурных запросов таблицы. Вообще-то это не так. Я тестировал .Substring() и .IndexOf(), и они не работают в запросах Azure Table, поэтому шансы .ToInt64() работать невелики.

Вы могли бы переформатировать это быть

s => s.PartitionKey > startTicks.ToString() + "_" 
&& s.PartitionKey < endTicks.ToString() + "_" 
&& s.RowKey == "story_" + searchGuid 

Это, скорее всего, не создает очень эффективный запрос, поскольку Azure может запутаться, если у вас есть два фильтра на основе ключа секционирования и просто делать сканирование таблицы. Другой вариант заключается в том, чтобы не включать часть запроса endTicks и когда вы обрабатываете результаты, когда вы переходите на один ключ раздела больше, чем конечные тики, прекратите обработку результатов.

Также ваш код, как вы его написали, не получит все элементы на основе токена продолжения, он просто получит первый набор результатов, которые будут возвращены. Я думаю, что ваш окончательный код должен выглядеть следующим образом (Неоткомпилированная, непроверенных и я уверен, что люди могут видеть некоторые улучшения производительности:

private class ListRowsContinuationToken 
{ 
    public string NextPartitionKey { get; set; } 
    public string NextRowKey { get; set; } 
} 

public Stories SelectStory(DateTime start, DateTime end, string searchGuid) 
{ 
    long startTicks = DateTime.MaxValue.Ticks - start.ToUniversalTime().Ticks; 
    long endTicks = DateTime.MaxValue.Ticks - end.ToUniversalTime().Ticks; 

var stories = _ServiceContext.CreateQuery<Story>("Story").Where(s => s.PartitionKey > startTicks.ToString() + "_" 
       && s.PartitionKey < endTicks.ToString() + "_" 
       && s.RowKey == "story_" + searchGuid).Take(50); 

var query = stories as DataServiceQuery<Story>; 

Stories finalList = new Stories(); 

var results = query.Execute(); 

ListRowsContinuationToken continuationToken = null; 
bool reachedEnd = false; 

do 
{ 
    if ((continuationToken != null)) 
    { 
     servicesQuery = servicesQuery.AddQueryOption("NextPartitionKey", continuationToken.NextPartitionKey); 

     if (!string.IsNullOrEmpty(continuationToken.NextRowKey)) 
     { 
      servicesQuery.AddQueryOption("NextRowKey", continuationToken.NextRowKey); 
     } 
    } 

    var response = (QueryOperationResponse<T>)query.Execute(); 

    foreach (Story result in response) 
    { 
     if (result.PartitionKey < endTicks.ToString()) 
     { 
      finalList.AddRange(result); 
     } 
     else 
     { 
      reachedEnd = true; 
     } 
    } 

    if (response.Headers.ContainsKey("x-ms-continuation-NextPartitionKey")) 
    { 
     continuationToken = new ListRowsContinuationToken 
     { 
      NextPartitionKey = response.Headers["x-ms-continuation-NextPartitionKey"] 
     }; 

     if (response.Headers.ContainsKey("x-ms-continuation-NextRowKey")) 
     { 
      continuationToken.NextRowKey = response.Headers["x-ms-continuation-NextRowKey"]; 
     } 
    } 
    else 
    { 
     continuationToken = null; 
    } 

} while (continuationToken != null && reachedEnd == false); 

return finalList; 

}

+0

Вы правы там была логическая ошибка, но она должна были: Convert.ToInt64 (s.RowKey.Substring (0, s.RowKey.IndexOf ("_"))) Вы также правы относительно токена продолжения, если я принимаю только некоторые результаты, тогда очевидно не будет токеном продолжения. Я собираюсь исправить это прямо сейчас и посмотреть, работает ли оно. Спасибо за помощь! Действительно оцените ответ - я провел весь день на этом. – rksprst

+0

I bel Диапазоны разделов ieve (например, x 0. – smarx

+0

Я продолжаю слышать противоречивые сообщения о том, что вы можете и не может использоваться в запросе, который ссылается на ключи разделов (разговоры о возможном сканировании таблицы пугают меня от меня). Возможно, кто-то должен создать каноническую ссылку и поместить ее в видео где-нибудь ...Кажется, это чисто академическое в этом случае, поскольку оно должно быть ключом строки в любом случае. – knightpfhor

Смежные вопросы