TableServiceContext和动态查询

时间:2011-05-12 10:11:14

标签: linq azure expression dataservice

我试图做一些看似非常简单的事情,但是当我想让它变得更有活力时,我遇到了很大的困难。

    Expression<Func<TableServiceEntity, bool>> predicate = (e) => e.PartitionKey == "model" && (e.RowKey == "home" || e.RowKey == "shared");

context.CreateQuery<TableServiceEntity>(tableName).Where(predicate);

我想传递一个rowKey数组,而不是硬编码谓词。

当我尝试构建表达式树时,我收到一个不受支持的异常,我认为它不支持在表达式树中调用。

有人知道如何构建和表达树与谓词完全相同,以避免不支持的异常吗?

先谢谢你

3 个答案:

答案 0 :(得分:2)

因此,您可以使用类似的东西动态构建查询(取自PhluffyFotos示例):

        Expression<Func<PhotoTagRow, bool>> search = null;
        foreach (var tag in tags)
        {
            var id = tag.Trim().ToLowerInvariant();

            if (String.IsNullOrEmpty(id))
            {
                continue;
            }

            Expression<Func<PhotoTagRow, bool>> addendum = t => t.PartitionKey == id;

            if (search == null)
            {
                search = addendum;
            }
            else
            {
                search = Expression.Lambda<Func<PhotoTagRow, bool>>(Expression.OrElse(search.Body, addendum.Body), search.Parameters);
            }
        }

现在,一旦你进行'搜索',你就可以将它作为谓词传递给你的Where子句。

然而,我想说服你不要这样做。我正在回答你的问题,但是告诉你做一个多重'|'是个坏主意表存储中的OR子句。原因是至少今天,这些查询无法进行优化,并且会导致全表扫描。任何非平凡的数据都会令人骇人听闻。此外,如果您像这样动态构建谓词,则存在破坏URL限制的风险(请记住这一点)。

PhluffyFotos中的这段代码展示了如何,但它实际上是一种不好的做法(我知道,我写了它)。它应该被优化以并行地单独运行每个OR子句。这就是你应该如何做到的。 AND子句是可以的,但OR子句应该并行化(使用PLINQ或TPL),你应该汇总结果。它会快得多。

HTH。

答案 1 :(得分:1)

我相信HTH所说的关于这种查询进行全表扫描的内容从我读过的文档中是不正确的。 Azure将执行PARTITION扫描而不是TABLE扫描,这在性能上有很大差异。

答案 2 :(得分:0)

这是我的解决方案,请阅读HTH的回答,他指出这不是最佳做法。

var parameter = Expression.Parameter(typeof(TableServiceEntity), "e");

var getPartitionKey = typeof(TableServiceEntity).GetProperty("PartitionKey").GetGetMethod();
var getRowKey = typeof(TableServiceEntity).GetProperty("RowKey").GetGetMethod();

var getPartition = Expression.Property(parameter, getPartitionKey);
var getRow = Expression.Property(parameter, getRowKey);

var constPartition = Expression.Constant("model", typeof(string));
var constRow1 = Expression.Constant("home", typeof(string));
var constRow2 = Expression.Constant("shared", typeof(string));

var equalPartition = Expression.Equal(getPartition, constPartition);
var equalRow1 = Expression.Equal(getRow, constRow1);
var equalRow2 = Expression.Equal(getRow, constRow2);

var and = Expression.AndAlso(equalPartition, Expression.OrElse(equalRow1, equalRow2));

return Expression.Lambda<Func<TableServiceEntity, bool>>(and, parameter);