Итак, вот моя дилемма. Я пытаюсь использовать 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, чтобы принять схему нового типа объекта. Не слишком много удачи там ... Я буду держать вас всех в курсе.