TableServiceContext и динамический запрос - PullRequest
1 голос
/ 12 мая 2011

Я пытаюсь сделать что-то, что выглядит очень просто, но я сталкиваюсь с огромными трудностями, когда хочу сделать это более динамичным.

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

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

Я бы хотел передать массив rowKey вместо необходимостизакодируйте предикат.

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

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

Заранее спасибо

Ответы [ 3 ]

2 голосов
/ 12 мая 2011

Итак, вы можете динамически построить запрос, используя что-то вроде этого (взято из PhluffyFotos sample):

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

Теперь, когда у вас есть 'search', вы можете просто передатьэто как предикат в вашем предложении Where.

Однако , я хочу убедить вас не делать этого.Я отвечаю на ваш вопрос, но говорю вам, что это плохая идея сделать несколько '|'ИЛИ предложение в таблице хранения.Причина в том, что, по крайней мере, сегодня эти запросы нельзя оптимизировать, и они вызывают полное сканирование таблицы.Производительность будет ужасной с любым нетривиальным количеством данных.Кроме того, если вы создаете свои предикаты динамически, как это, вы рискуете нарушить ограничение URL (имейте это в виду).

Этот код в PhluffyFotos показывает, как, но на самом деле это плохая практика (я знаю,Я это написал).Он действительно должен быть оптимизирован для параллельного запуска каждого предложения OR.Вот как вы действительно должны это делать.Предложения AND в порядке, но предложения OR должны быть распараллелены (используйте PLINQ или TPL), и вы должны агрегировать результаты.Это будет намного быстрее.

HTH.

1 голос
/ 12 октября 2011

Я полагаю, что то, что HTH сказал об этом типе запроса при полном сканировании таблицы, неверно из документации, которую я прочитал. Azure будет выполнять сканирование PARTITION, а не сканирование TABLE, что сильно влияет на производительность.

0 голосов
/ 14 мая 2011

Вот мое решение, пожалуйста, прочтите также ответ 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);
...