我正在动态创建LINQ查询,到目前为止我做的还可以。
但我被困在我认为不会的地方。在构建该查询的某个点上,我需要访问实体的EnityCollection。像这样:
Expression collection = Expression.Property(entity, typeof(EntityType).GetProperty("CollectionOfRelatedEntities"));
然后,我会在该集合上调用“Where”LINQ方法:
MethodCallExpression AfterWhere = Expression.Call(
typeof(Queryable),
"Where",
new Type[] { typeof(RelatedEntity) },
collection,
Expression.Lambda<Func<RelatedEntity, bool>>(predicate, new ParameterExpression[] { paramOfRelatedEntity }));
通常这会奏效。在这种情况下,它不会因为集合是IEnumerable而我需要它是IQueryable才能使“Where”工作。
我试过了:
Expression.Convert(collection, typeof(IQueryable<RelatedEntity>);
但是它说无法强制转换因为EntityCollection没有实现IQueryable。
我静态地使用AsQueryable来实现我需要的东西,所以我尝试动态地模仿它:
Expression.Call(collection, typeof(EntityCollection<RelatedEntity>).GetMethod("AsQueryable"));
但我得到null引用异常。我无法通过反思达到它。这个AsQueryable方法是扩展方法,它是静态的,在Queryable类中定义,所以我试过:
Expression.Call(collection, typeof(Queryable).GetMethod("AsQueryable", BindingFlags.Static));
相同的结果:“值不能为空”。
我在这里达到了极限,我的想法很新鲜。
所以,我问你:
如何动态地将IEnumerable转换为IQueryable?
答案 0 :(得分:5)
尝试以这种方式获取方法:
var method = typeof(Queryable).GetMethod(
"AsQueryable",
BindingFlags.Static | BindingFlags.Public,
null,
new [] { typeof(IEnumerable<RelatedEntity>)},
null);
然后,您应该能够像这样构建对该方法的调用:
Expression.Call(method, collection);
您的代码存在的问题是BindingFlags使用起来很棘手。如果你指定任何BindingFlags - 比如BindingFlags.Static - 那么你还必须明确说明你是否想要BindingFlags.Public或BindingFlags.NonPublic。
然后第二个问题是有两个AsQueryable方法 - 一个通用方法和一个非通用方法。提供类型参数数组可以解决这种歧义。
答案 1 :(得分:2)
“通常情况下会有效。在这种情况下,它不会因为集合是IEnumerable而我需要IQueryable才能使”Where“工作。”
不,你没有。对于可枚举,请使用Enumerable.Where
代替Queryable.Where
。
var query =
from customer in Context.Customers
where customer.Id == YourCustomerId // 1
select new
{
Customer = customer,
OrderCount = customer.Orders.Where(order => order.IsOpen).Count() // 2
};
第一个“where”解析为Queryable.Where
,但第二个不解析,Enumerable.Where
。这不是问题或效率低,因为整个表达式是子查询的一部分,因此仍将发送到查询提供程序并将(f.e.)转换为SQL。
答案 2 :(得分:0)
好的,我想我明白了:
首先,通过反思得到方法,因为伊戈尔说:
MethodInfo mi = typeof(Queryable).GetMethod("AsQueryable", BindingFlags.Static | BindingFlags.Public, null, new [] { typeof(IEnumerable<RelatedEntity>) }, null);
然后,我使用了不同版本的Expression.Call来克服静态/实例不匹配:
Expression buff = Expression.Call(mi, new[] { collection });
最后将其转换为类型化的AsQueryable:
Expression final = Expression.Convert(buff, typeof(IQueryable<RelatedEntity>));