访问 Azure 表时出现“不支持表达式”错误

发布于 2024-09-27 08:14:52 字数 3297 浏览 3 评论 0原文

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

I'm trying to get some records from the Azure Table Storage while using paging with the continuation token.

I have the following code:

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

But I'm getting the following error:

 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. 

I'm not sure why the expression is not allowed. Does anyone have any ideas how I can change it to get it to work?

Thanks!

Edit: the new code (no errors but no data gets selected - even though i know it exists):

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

征棹 2024-10-04 08:14:52

好吧,我认为这里发生了一些事情。我认为其中有一个逻辑缺陷。不应该

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

其次

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

,您需要非常小心天蓝色表查询支持哪些功能。一般来说,他们不是。我已经测试了 .Substring().IndexOf(),它们在 Azure 表查询中不起作用,因此 .ToInt64()< 的可能性/code> 工作几乎没有。

您可以将其重新格式化为:

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;

}

OK, I think there are a couple of things going on here. One I think there is a logic flaw. Shouldn't

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

be

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

Secondly you need to be very careful about which functions are supported by azure table queries. Generally they're not. I've tested .Substring() and .IndexOf() and they don't work in Azure Table queries, so the chances of .ToInt64() working is slim to none.

You might be able to reformat this to be

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

This will likely not generate a very efficient query because Azure can get confused if you have two filters based on partition key and just do a table scan. Another option is to not include the endTicks part of the query and when you process the results, when you get to one the partition key is greater than end ticks, stop processing the results.

Also your code as you have it written won't get all of the items based on the continuation token, it will just get the first set of results that are returned. I think your final code should look something like this (uncompiled, untested and I'm sure people can see some performance improvements:

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;

}

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文