Alex Zhukovskiy
Alex Zhukovskiy

Reputation: 10015

How do I perform IQueryable requests in MongoDB?

I'm trying to connect some framework that is based on IQueryable interface (i.e. OData if you wonder).

My current problem can be described using following snippet:

var queryable = database.GetCollection<MyItems>("myItems").AsQueryable();
var count1 = queryable.Select(x => x.Order.StateInfo).Count();
// var count2 = queryable.Select(x => x.Order).Select(x => x.StateInfo).Count();

This code works but if you uncomment the last line you get:

System.ArgumentException: Expression of type 'System.Collections.Generic.IEnumerable`1[MyApp.Common.Models.StateInfo]' 
cannot be used for parameter of type 'System.Linq.IQueryable`1[MyApp.Common.Models.StateInfo]' of method
 'Int32 Count[StateInfo](System.Linq.IQueryable`1[MyApp.Common.Models.StateInfo])' (Parameter 'arg0')
   at System.Dynamic.Utils.ExpressionUtils.ValidateOneArgument(MethodBase method, ExpressionType nodeKind, Expression arguments, ParameterInfo pi, String methodParamName, String argumentParamName, Int32 index)
   at System.Linq.Expressions.Expression.Call(MethodInfo method, Expression arg0)
   at System.Linq.Expressions.MethodCallExpression1.Rewrite(Expression instance, IReadOnlyList`1 args)
   at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at MongoDB.Driver.Linq.Processors.Transformer.Visit(Expression node)
   at MongoDB.Driver.Linq.Processors.Transformer.Transform(Expression node)
   at MongoDB.Driver.Linq.MongoQueryProviderImpl`1.Prepare(Expression expression)
   at MongoDB.Driver.Linq.MongoQueryProviderImpl`1.Translate(Expression expression)
   at MongoDB.Driver.Linq.MongoQueryProviderImpl`1.ExecuteAsync[TResult](Expression expression, CancellationToken cancellationToken)
   at MongoDB.Driver.Linq.MongoQueryable.CountAsync[TSource](IMongoQueryable`1 source, CancellationToken cancellationToken)

It seems that driver tries to perform some operations in-memory, dropping the whole IQueryable thing, so all the subsequent calls fail (like Select/Where/...). Query with two subsequent Select's or Select/Where pair get efficiently poisoned and cannot be used anywhere. For example:

var queryable = database.GetCollection<MyItems>("myItems").AsQueryable();
var count1 = queryable.Select(x => x.Order).Where(x => x.StateInfo != null).Count(); 
// System.InvalidOperationException: '{document}.StateInfo is not supported.'

What can I do about it? Maybe I can report it somewhere?

Upvotes: 3

Views: 3668

Answers (1)

Victor Trusov
Victor Trusov

Reputation: 1222

MongoDB C# Driver just partially supports IQueryable because it's too hard to implement all cases with MongoDB aggregation pipeline.

So I'm not surprised if version 2.10 doesn't support Select out of another Select and Where out of Select.

Can't find any info about this in current documentation but here from v1 doc:

Select is used to project a new result type from the matching documents. A projection must typically be the last operation (with a few exceptions like Distinct, Max and Min).

Using IQueryable is limited to basic methods described here.
And here you can find IQueryable tests, where again I can't find .Select().Select().

Upvotes: 1

Related Questions