Использование Dynamic LINQ (или Generics) для запроса / фильтрации таблиц Azure - PullRequest
1 голос
/ 17 сентября 2010

Итак, вот моя дилемма. Я пытаюсь использовать Dynamic LINQ для анализа поискового фильтра для получения набора записей из таблицы Azure. В настоящее время я могу получить все записи, используя объект GenericEntity, определенный ниже:

public class GenericEntity
{
    public string PartitionKey { get; set; }
    public string RowKey { get; set; }

    Dictionary<string, object> properties = new Dictionary<string, object>();
    /* "Property" property and indexer property omitted here */
}

Я могу получить это полностью заполненным, используя событие ReadingEntity объекта TableServiceContext (называемое OnReadingGenericEvent). Следующий код - это то, что фактически извлекает все записи и фильтр , мы надеемся, (как только он заработает).

public IEnumerable<T> GetTableRecords(string tableName, int numRecords, string filter)
{
    ServiceContext.IgnoreMissingProperties = true;

    ServiceContext.ReadingEntity -= LogType.GenericEntity.OnReadingGenericEntity;
    ServiceContext.ReadingEntity += LogType.GenericEntity.OnReadingGenericEntity;

    var result = ServiceContext.CreateQuery<GenericEntity>(tableName).Select(c => c);
    if (!string.IsNullOrEmpty(filter))
    {
        result = result.Where(filter);
    }
    var query = result.Take(numRecords).AsTableServiceQuery<GenericEntity>();
    IEnumerable<GenericEntity> res = query.Execute().ToList();

    return res;
}

У меня есть производные типы TableServiceEntity для всех таблиц, которые я определил, поэтому я могу получить все свойства / типы, используя Reflection. Проблема с использованием класса GenericEntity в динамическом запросе LINQ для фильтрации заключается в том, что объект GenericEntity НЕ имеет каких-либо свойств, по которым я пытаюсь фильтровать, поскольку они на самом деле являются просто записями словаря (ошибки динамического запроса). Я могу разобрать фильтр для всех имен свойств этого конкретного типа и обернуть

"Property[" + propName + "]" 

вокруг каждого свойства (найдено с помощью функции распознавания типов и отражения). Тем не менее, это кажется немного ... излишним. Я пытаюсь найти более элегантное решение, но поскольку мне действительно нужно предоставить тип в ServiceContext.CreateQuery <>, это делает его несколько сложным.

Так что я думаю, что мой последний вопрос заключается в следующем: как я могу использовать динамические классы или универсальные типы с этой конструкцией, чтобы иметь возможность использовать динамические запросы для фильтрации? Таким образом, я могу просто взять фильтр из текстового поля (например, "item_ID> 1023000") и просто динамически генерировать типы TableServiceEntity.

Есть другие способы, которыми я могу воспользоваться, но я подумал, что с тех пор, как я начал использовать Dynamic LINQ, можно также попробовать Dynamic Classes.

Редактировать: Итак, у меня есть динамический класс, сгенерированный начальным выбором с использованием некоторого отражения, но я сталкиваюсь с препятствиями в отображении типов GenericEntity.Properties в различные записи связанной таблицы классы (производные классы TableServiceEntity) и типы их свойств. Основная проблема по-прежнему заключается в том, что мне сначала нужно использовать определенный тип данных, чтобы даже создать запрос, поэтому я использую тип GenericEntity, который содержит только пары KV. Это в конечном итоге мешает мне фильтровать, так как я не могу выполнять операторы сравнения (>, <, = и т. Д.) С типами объектов. </p>

Вот код, который я сейчас должен сделать для отображения в динамический класс:

var properties = newType./* omitted */.GetProperties(
    System.Reflection.BindingFlags.Instance |
    System.Reflection.BindingFlags.Public);

string newSelect = "new(" + properties.Aggregate("", (seed, reflected) => seed += string.Format(", Properties[\"{0}\"] as {0}", reflected.Name)).Substring(2) + ")";
var result = ServiceContext.CreateQuery<GenericEntity>(tableName).Select(newSelect);

Может быть, мне стоит просто изменить метод properties.Aggregate, чтобы префикс раздела «Properties [...]» отражать .PropertyType? Таким образом, новая строка выбора будет выглядеть так:

string newSelect = "new(" + properties.Aggregate("", (seed, reflected) => seed += string.Format(", ({1})Properties[\"{0}\"] as {0}", reflected.Name, reflected.PropertyType)).Substring(2) + ")";

Редактировать 2: Так что теперь у меня довольно много препятствий. Я могу сгенерировать анонимные типы для всех таблиц, чтобы получить все нужные мне значения, но LINQ избавит меня от того, что я делаю для фильтра. Я изложил причину выше (без операторов сравнения для объектов), но проблема, с которой я сейчас сталкиваюсь, заключается в попытке указать параметр типа для метода расширения Dynamic LINQ, чтобы принять схему нового типа объекта. Не слишком много удачи там ... Я буду держать вас всех в курсе.

Ответы [ 3 ]

2 голосов
/ 01 октября 2012

Я создал простое решение на основе System.Refection.Emit для создания класса, который вам нужен во время выполнения.http://blog.kloud.com.au/2012/09/30/a-better-dynamic-tableserviceentity/

0 голосов
/ 20 сентября 2010

Так что я нашел способ сделать это, но это не очень красиво ...

Поскольку я не могу действительно делать то, что хочу в самой среде, я использовал концепцию, используемую в проекте AzureTableQuery . У меня просто большая строка кода на C #, которая компилируется на лету с нужным мне объектом. Если вы посмотрите на код проекта AzureTableQuery , вы увидите, что отдельная библиотека на лету компилируется для любой таблицы, которая у нас есть, которая проходит и строит все необходимые нам свойства и вещи по мере необходимости. запросить таблицу. Не самое элегантное или легкое решение, но, тем не менее, оно работает.

Серьезно желаю, чтобы был лучший способ сделать это, но, к сожалению, это не так просто, как я надеялся. Надеюсь, кто-то сможет извлечь уроки из этого опыта и, возможно, найти лучшее решение, но у меня уже есть то, что мне нужно, поэтому я над этим поработал (пока).

0 голосов
/ 17 сентября 2010

Я столкнулся с точно такой же проблемой (почти с тем же кодом :-)).У меня есть подозрение, что классы ADO.NET, расположенные внизу, каким-то образом не взаимодействуют с динамическими типами, но еще не нашли точно, где.

...