2010-10-11 36 views
0

J'essaie d'obtenir des enregistrements du stockage de table Azure en utilisant la pagination avec le jeton de continuation.L'erreur d'expression n'est pas prise en charge lors de l'accès aux tables Azure

J'ai le code suivant:

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; 
} 

Mais je reçois l'erreur suivante:

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. 

Je ne sais pas pourquoi l'expression est pas autorisée. Est-ce que quelqu'un a des idées sur comment je peux le changer pour le faire fonctionner?

Merci!

Edit: le nouveau code (aucune erreur mais aucune donnée ne se sélectionné - même si je sais qu'il existe):

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; 
    } 

Répondre

1

OK, je pense qu'il ya deux choses qui se passent ici. Un je pense qu'il y a un défaut logique. Ne devrait pas

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

être

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

Deuxièmement, vous devez être très prudent sur les fonctions sont prises en charge par des requêtes de table azur. Généralement ils ne le sont pas. J'ai testé .Substring() et .IndexOf() et ils ne fonctionnent pas dans les requêtes de tableau Azure, donc les chances de .ToInt64() de travail est mince à aucun.

Vous pourriez être en mesure de reformater que ce soit

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

Cela ne sera probablement pas générer une requête très efficace, car Azure peut se confondre si vous avez deux filtres basés sur la touche de partition et juste faire une analyse de table. Une autre option consiste à ne pas inclure la partie endTicks de la requête et lorsque vous traitez les résultats, lorsque vous atteignez l'une des clés de partition est plus grande que les ticks d'extrémité, arrêtez le traitement des résultats.

Aussi votre code comme vous l'avez écrit n'obtiendra pas tous les éléments basés sur le jeton de continuation, il obtiendra juste le premier ensemble de résultats qui sont retournés. Je pense que votre code final devrait ressembler à ceci (interprétée, non testé et je suis sûr que les gens peuvent voir des améliorations de performance:

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

Vous avez raison il y avait une erreur logique, mais il faut ont été: Convert.ToInt64 (s.RowKey.Substring (0, s.RowKey.IndexOf ("_"))) Vous avez également raison sur le jeton de continuation, si je ne prends que quelques résultats alors là évidemment Je ne vais pas être un jeton de continuation Je vais essayer de le réparer dès maintenant et voir si cela fonctionne.Merci pour l'aide! J'apprécie vraiment une réponse - J'ai passé toute la journée sur ce sujet – rksprst

+0

I bel Les plages de partition de ieve (comme x 0. – smarx

+0

Je continue d'entendre des messages contradictoires sur ce que vous pouvez et ne peut pas utiliser dans une requête qui fait référence à des clés de partition (parler de possibles scans de table me fait peur). Peut-être que quelqu'un devrait produire une référence canonique et la mettre en vidéo quelque part ...Il semble que c'est purement académique dans ce cas, car il est censé être la clé de la rangée de toute façon. – knightpfhor