访问Azure表时,表达式不受支持错误

时间:2010-10-11 20:02:23

标签: c# azure azure-storage azure-table-storage

我正在尝试使用带有延续令牌的分页从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. 

我不确定为什么表达式不被允许。有没有人有任何想法如何改变它以使其发挥作用?

谢谢!

编辑:新代码(没有错误,但没有数据被选中 - 即使我知道它存在):

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 个答案:

答案 0 :(得分:1)

好的,我认为这里有几件事情。我认为存在一个逻辑缺陷。不应该

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

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

其次,您需要非常小心天蓝色表查询支持哪些功能。一般来说,他们不是。我已经测试了.Substring().IndexOf(),但它们在Azure表查询中不起作用,因此.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;

}