所以这就是我的困境。我正在尝试利用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 */
}
我可以通过使用TableServiceContext对象的ReadingEntity事件(称为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获取所有属性/类型。在动态LINQ查询中使用GenericEntity类进行过滤的问题是GenericEntity对象没有我试图过滤的任何属性,因为它们实际上只是字典条目(动态查询错误输出)。我可以解析该特定类型的所有属性名称的过滤器并包装
"Property[" + propName + "]"
围绕每个属性(通过使用类型解析器函数和反射找到)。然而,这似乎有点......过度杀伤力。我正在尝试找到一个更优雅的解决方案,但由于我实际上必须在ServiceContext.CreateQuery&lt;&gt;中提供一个类型,这使得它有点困难。
所以我想我的最终问题是:如何使用动态类或泛型类型来构建能够利用动态查询进行过滤?这样我就可以从文本框(例如“item_ID&gt; 1023000”)中获取过滤器,并且只是动态生成TableServiceEntity类型。
我可以利用其他方法,但我想,自从我开始使用Dynamic LINQ以来,也可以尝试动态类。
编辑:所以我通过初始选择使用一些反射来生成动态类,但是我在将GenericEntity.Properties的类型映射到各种关联表中时遇到了障碍记录类(TableServiceEntity派生类)及其属性类型。主要问题仍然是我必须最初使用特定的数据类型甚至创建查询,所以我使用的GenericEntity类型只包含KV对。这最终阻止我进行过滤,因为我无法对对象类型进行比较运算符(&gt;,&lt;,=等)。
以下是我现在要映射到动态类的代码:
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 [...]”部分前面加上reflect.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扩展方法指定一个类型参数来接受新对象类型的模式。那里运气不多,要么......我会把你全部贴出去。
答案 0 :(得分:2)
我创建了一个简单的基于System.Refection.Emit的解决方案来创建运行时所需的类。 http://blog.kloud.com.au/2012/09/30/a-better-dynamic-tableserviceentity/
答案 1 :(得分:0)
我遇到了完全相同的问题(几乎相同的代码:-))。我怀疑下面的ADO.NET类在某种程度上不与动态类型合作,但还没有找到确切的位置。
答案 2 :(得分:0)
所以我找到了一种方法,但它不是很漂亮......
由于我无法在框架内实际执行我想要的操作,因此我使用了AzureTableQuery项目中使用的概念。我几乎只有一个大的C#代码字符串,可以使用我需要的确切对象动态编译。如果你看一下AzureTableQuery项目的代码,你会看到我们已经为我们拥有的任何表格动态编译了一个单独的库,它会遍历并构建我们查询时所需的所有属性和内容。表。不是最优雅或最轻便的解决方案,但它仍然有效。
真的希望有更好的方法来做到这一点,但不幸的是,这并不像我希望的那么容易。希望有人能够从这种经验中学习,并可能找到更好的解决方案,但我已经拥有了我所需要的东西,所以我已经完成了它(现在)。