Dynamically throw IEnumerable into IQueryable or dynamically call AsQueryable using LINQ expressions

I am creating a LINQ query dynamically, and so far everything is fine.

But I got stuck where I thought I wouldn’t. At some point when creating this request, I need to access the EntityCollection element of an object. Something like that:

Expression collection = Expression.Property(entity, typeof(EntityType).GetProperty("CollectionOfRelatedEntities")); 

Then I would call the LINQ Where method for this collection:

 MethodCallExpression AfterWhere = Expression.Call( typeof(Queryable), "Where", new Type[] { typeof(RelatedEntity) }, collection, Expression.Lambda<Func<RelatedEntity, bool>>(predicate, new ParameterExpression[] { paramOfRelatedEntity })); 

And usually it will work. In this case, this will not happen because the collection is IEnumerable, and I need it to be IQueryable in order for "Where" to work.

I tried this:

 Expression.Convert(collection, typeof(IQueryable<RelatedEntity>); 

but he says he cannot be started because EntityCollection does not implement IQueryable.

I statically use AsQueryable to achieve what I need here, so I tried to simulate this dynamically:

 Expression.Call(collection, typeof(EntityCollection<RelatedEntity>).GetMethod("AsQueryable")); 

but I get an exception to exclude links. I cannot achieve this through reflection. This AsQueryable method is an extension method, it is static defined in the Queryable class, so I tried:

 Expression.Call(collection, typeof(Queryable).GetMethod("AsQueryable", BindingFlags.Static)); 

Same result: "Value cannot be null."

I am reaching my limits here, and I am fresh from ideas.

So I ask you:

How can I dynamically port IEnumerable to IQueryable?

+8
c # dynamic linq
source share
3 answers

Try to get the method as follows:

 var method = typeof(Queryable).GetMethod( "AsQueryable", BindingFlags.Static | BindingFlags.Public, null, new [] { typeof(IEnumerable<RelatedEntity>)}, null); 

Then you can construct a call to this method as follows:

 Expression.Call(method, collection); 

The problem with your code was that BindingFlags are hard to use. If you specify any BindingFlags β€” for example, BindingFlags.Static β€” then you must also explicitly indicate whether you want BindingFlags.Public or BindingFlags.NonPublic.

Then the second problem is that there are two AsQueryable methods - general and not general. Providing an array of type arguments resolves this ambiguity.

+5
source share

β€œAnd it usually works. In this case, it’s not because the collection is IEnumerable, and I need it to be IQueryable, so thatβ€œ where to work ”.

No no. For enumeration, use Enumerable.Where instead of 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 }; 

The first "where" resolves Queryable.Where , but the second does not do that Enumerable.Where . This is not a problem or inefficiency, because the whole expression is part of a subquery, so it will still be sent to the query provider and (fe) translated into SQL.

+2
source share

Ok, I think I get it:

First, get the method through reflection, as Igor said:

 MethodInfo mi = typeof(Queryable).GetMethod("AsQueryable", BindingFlags.Static | BindingFlags.Public, null, new [] { typeof(IEnumerable<RelatedEntity>) }, null); 

then I used a different version of Expression.Call to overcome the static / instance mismatch:

 Expression buff = Expression.Call(mi, new[] { collection }); 

and finally drop it on a typed AsQueryable:

 Expression final = Expression.Convert(buff, typeof(IQueryable<RelatedEntity>)); 
0
source share

All Articles