[CSHARP-3116] IQueryable breaks if query is prefixed with SELECT statement Created: 28/May/20  Updated: 28/Oct/23  Resolved: 16/Feb/22

Status: Closed
Project: C# Driver
Component/s: Linq
Affects Version/s: 2.10.4
Fix Version/s: 2.14.0

Type: Bug Priority: Major - P3
Reporter: Alex Zhuk Assignee: Unassigned
Resolution: Fixed Votes: 0
Labels: odata
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Epic Link: CSHARP-3615
Case:

 Description   

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.'



 Comments   
Comment by James Kovacs [ 16/Feb/22 ]

This issue has been fixed in the new LINQ provider (known as LINQ3), which is included in the 2.14 release.

Configure your MongoClientSettings to use LinqProvider.V3 if you want to use this functionality.

To configure a client to use the LINQ3 provider use code like the following

var connectionString = "mongodb://localhost";
var clientSettings = MongoClientSettings.FromConnectionString(connectionString);
clientSettings.LinqProvider = LinqProvider.V3;
var client = new MongoClient(clientSettings);

Comment by Robert Stam [ 02/Jun/20 ]

I can reproduce this with the following code:

using MongoDB.Driver;
using System.Linq;
 
namespace ConsoleApp2
{
    public class Order
    {
        public int StateInfo { get; set; }
    }
 
    public class MyItems
    {
        public Order Order { get; set; }
    }
 
    public static class Program
    {
        public static void Main(string[] args)
        {
            var client = new MongoClient("mongodb://localhost");
            var database = client.GetDatabase("test");
            var collection = database.GetCollection<MyItems>("test");
 
            var queryable = collection.AsQueryable();
            var count = queryable.Select(x => x.Order).Select(x => x.StateInfo).Count();
        }
    }
}

Not sure what the cause is yet.

Generated at Wed Feb 07 21:44:24 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.