[CSHARP-4957] IMongoCollection.AsQueryable().Select() fails for array type (regression) Created: 06/Feb/24  Updated: 07/Feb/24

Status: Investigating
Project: C# Driver
Component/s: LINQ3
Affects Version/s: 2.19.0, 2.23.1
Fix Version/s: None

Type: Bug Priority: Major - P3
Reporter: Evgeny Morozov Assignee: Robert Stam
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Assigned Teams:
Dotnet Drivers

 Description   

Summary

 
// IMongoCollection<TestClass> collection;collection.AsQueryable().Select(t => (IEnumerable<int>) new[] { t.Integer }).ToArray()
throws the following exception on 2.23.1:

MongoDB.Driver.Linq.ExpressionNotSupportedException: Expression not supported: t => new [] {t.Integer} because lambda body type is not convertible to lambda return type.
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.ExpressionToAggregationExpressionTranslator.TranslateLambdaBody(TranslationContext context, LambdaExpression lambdaExpression, IBsonSerializer parameterSerializer, Boolean asRoot)
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToPipelineTranslators.SelectMethodToPipelineTranslator.Translate(TranslationContext context, MethodCallExpression expression)
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToPipelineTranslators.ExpressionToPipelineTranslator.Translate(TranslationContext context, Expression expression)
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToExecutableQueryTranslators.ExpressionToExecutableQueryTranslator.Translate[TDocument,TOutput](MongoQueryProvider`1 provider, Expression expression)
   at MongoDB.Driver.Linq.Linq3Implementation.MongoQuery`2.Execute()
   at MongoDB.Driver.Linq.Linq3Implementation.MongoQuery`2.GetEnumerator()
   at System.Collections.Generic.LargeArrayBuilder`1.AddRange(IEnumerable`1 items)
   at System.Collections.Generic.EnumerableHelpers.ToArray[T](IEnumerable`1 source)
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)

Please provide the version of the driver. If applicable, please provide the MongoDB server version and topology (standalone, replica set, or sharded cluster).

2.23.1

Additional Background

This works on 2.18.0. From 2.19.0 it fails, though with a different (worse) exception message:{{{}
{}}}

System.InvalidCastException: Unable to cast object of type 'MongoDB.Driver.Linq.Linq3Implementation.Serializers.WrappedValueSerializer`1[System.Collections.Generic.IEnumerable`1[System.Int32]]' to type 'MongoDB.Bson.Serialization.IBsonSerializer`1[System.Int32[]]'.
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToExecutableQueryTranslators.ExecutableQuery`3.CreateCollectionPipelineDefinition()
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToExecutableQueryTranslators.ExecutableQuery`3.Execute(IClientSessionHandle session, CancellationToken cancellationToken)
   at MongoDB.Driver.Linq.Linq3Implementation.MongoQuery`2.Execute()
   at MongoDB.Driver.Linq.Linq3Implementation.MongoQuery`2.GetEnumerator()
   at System.Collections.Generic.LargeArrayBuilder`1.AddRange(IEnumerable`1 items)
   at System.Collections.Generic.EnumerableHelpers.ToArray[T](IEnumerable`1 source)
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)

 

A workaround is to cast the lambda result to IEnumerable<T>:

.AsQueryable().Select(t => (IEnumerable<int>) new[] { t.Integer }).ToArray();
 
This is a bit of a "gotcha" though, as it's hard to find all places in our code that may be affected by it (and of course the results then have to be cast back to array somewhere if the caller expects that).



 Comments   
Comment by Robert Stam [ 07/Feb/24 ]

Now that I have the parenthesis in the same place that you do I also get the same exception that you got.

I will investigate further.

Thanks for noticing that my test was different than your code.

Comment by Robert Stam [ 07/Feb/24 ]

Sorry I read your code wrong. I will change the test and see if I get the same error you do.

Comment by Evgeny Morozov [ 07/Feb/24 ]

Also,

var queryable = collection.AsQueryable()
    .Select(x => (new[] { x.Integer }).ToArray());

is not the same as my code. The brackets are placed differently, giving it a different meaning.

Comment by Evgeny Morozov [ 07/Feb/24 ]

Hi Robert, have you tested it on either of the two versions in "Affects Version/s"?

Comment by Robert Stam [ 06/Feb/24 ]

I am unable to reproduce this.

I used the following test statement:

var queryable = collection.AsQueryable()
    .Select(x => (new[] { x.Integer }).ToArray());

When using LINQ2 this throws a `NotSupportedException`.

When using LINQ3 this translates to the following aggregation pipeline:

{ $project : { _v : ['$Integer'], _id : 0 } } 

I tested against the latest version of the driver source code on the master branch. Let me know if this is only failing in a particular version of the driver.

Calling ToArray on something that is already an array is redundant, but it is legal and should work.

Comment by Evgeny Morozov [ 06/Feb/24 ]

Sorry, the code in "Summary" is with the workaround, and it seems that I cannot edit it. The code that fails is
 
// IMongoCollection<TestClass> collection;

var thisFails = collection.AsQueryable().Select(t => new[] { t.Integer }).ToArray();
 

Comment by PM Bot [ 06/Feb/24 ]

Hi evgeny+mongodb@loop54.com, thank you for reporting this issue! The team will look into it and get back to you soon.

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