[CSHARP-4650] LINQ3 provider: ValueType 'X' of parameterSerializer does not match parameter type 'Y' (where X is a subclass of Y) Created: 11/May/23  Updated: 12/May/23  Resolved: 12/May/23

Status: Closed
Project: C# Driver
Component/s: LINQ3
Affects Version/s: 2.19.1
Fix Version/s: None

Type: Bug Priority: Minor - P4
Reporter: Roberto Pérez Assignee: Robert Stam
Resolution: Duplicate Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Duplicate
duplicates CSHARP-4535 Client cannot resolve serializer anym... Backlog
Documentation Changes Summary:

1. What would you like to communicate to the user about this feature?
2. Would you like the user to see examples of the syntax and/or executable code and its output?
3. Which versions of the driver/connector does this apply to?


 Description   

Summary

The latest MongoDB.Driver for C# switched the default LINQ Provider from 2 to 3. After trying to upgrade and use version 3 the code that used to work in V2 fails in V3.

Server versions: 5.0.13 Windows and 5.0.10 Ubuntu

How to Reproduce

    internal class Program
    {
        private static void Main(string[] args)
        {
            foreach (var linqProvider in new []\{ LinqProvider.V2, LinqProvider.V3})
            {
                var builder = new MongoUrlBuilder
                {
                    DatabaseName = "Sample",
                    Server = new MongoServerAddress("localhost", 27017)
                };
                var mongoClientSettings = MongoClientSettings.FromUrl(builder.ToMongoUrl());
                mongoClientSettings.LinqProvider = linqProvider;
                var mongoClient = new MongoClient(mongoClientSettings);
                var mongoDatabase = mongoClient.GetDatabase(builder.DatabaseName);
 
                var licensePlate = "5555XXX";
 
                var carCollection = mongoDatabase.GetCollection<Car>("Cars");
                carCollection.DeleteMany(c => true);
                carCollection.InsertOne(new Car
                {
                    Id = licensePlate,
                    Description = $"\{linqProvider} - Description for license: \{licensePlate}"
                });
 
                var deletedCarCollection = mongoDatabase.GetCollection<DeletedCar>("DeletedCars");
                deletedCarCollection.DeleteMany(c => true);
                deletedCarCollection.InsertOne(new DeletedCar
                {
                    Id = licensePlate,
                    Description = $"\{linqProvider} - Deleted - Description for license: \{licensePlate}",
                    DeletedDate = DateTime.UtcNow.AddDays(-1)
                });
 
                Console.WriteLine(GetCarDescription_Works(carCollection.AsQueryable(), licensePlate));
                Console.WriteLine(GetCarDescription_Works(deletedCarCollection.AsQueryable(), licensePlate));
                Console.WriteLine();
                Console.WriteLine(GetCarDescription_Fails(carCollection.AsQueryable(), licensePlate));
                Console.WriteLine(GetCarDescription_Fails(deletedCarCollection.AsQueryable(), licensePlate));
                Console.WriteLine();
                Console.WriteLine();
            }
        }
 
        private static string GetCarDescription_Works<T>(IQueryable<T> queryable, string licensePlate) where T : Car
        {
            return queryable.Where(d => d.Id == licensePlate).Select(d => d.Description).FirstOrDefault();
        }
 
        private static string GetCarDescription_Fails(IQueryable<Car> queryable, string licensePlate)
        {
            return queryable.Where(d => d.Id == licensePlate).Select(d => d.Description).FirstOrDefault();
        }
 
        private class Car
        {
            public string Id \{ get; set; }
            public string Description \{ get; set; }
        }
 
        private class DeletedCar : Car
        {
            public DateTime DeletedDate \{ get; set; }
        }
    }

 

Execution output:

Description for license: 5555XXX
Deleted - Description for license: 5555XXX
 
Description for license: 5555XXX
 
Unhandled Exception: System.ArgumentException: ValueType 'Sample.Program+DeletedCar' of parameterSerializer does not match parameter type 'Sample.Program+Car'.
Parameter name: parameterSerializer
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToFilterTranslators.ExpressionToFilterTranslator.TranslateLambda(TranslationContext context, LambdaExpression lambdaExpression, IBsonSerializer parameterSerializer, Boolean asRoot)
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToPipelineTranslators.WhereMethodToPipelineTranslator.Translate(TranslationContext context, MethodCallExpression expression)
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToPipelineTranslators.ExpressionToPipelineTranslator.Translate(TranslationContext context, Expression expression)
   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.FirstMethodToExecutableQueryTranslator`1.Translate[TDocument](MongoQueryProvider`1 provider, TranslationContext context, MethodCallExpression expression)
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToExecutableQueryTranslators.ExpressionToExecutableQueryTranslator.TranslateScalar[TDocument,TResult](MongoQueryProvider`1 provider, Expression expression)
   at MongoDB.Driver.Linq.Linq3Implementation.MongoQueryProvider`1.Execute[TResult](Expression expression)
   at System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source)
   at Sample.Program.GetCarDescription_Fails(IQueryable`1 queryable, String licensePlate) in D:\tfs2015\Shared\Packages\Panda.DataAccess\Sample\Program.cs:line 53
   at Sample.Program.Main(String[] args) in D:\tfs2015\Shared\Packages\Panda.DataAccess\Sample\Program.cs:line 43



 Comments   
Comment by Robert Stam [ 12/May/23 ]

I am able to reproduce this with the code you have provided. Thanks for making it easy to reproduce.

The issue arises because in the one scenario that doesn't work you are passing an instance of `IMongoQueryable<DeletedCar>` to the first parameter of `GetCarDescription_Fails` and this parameter is of type `IQueryable<Car>`. This compiles because of covariance.

This is the same issue as reported in CSHARP-4535 so I am closing this issue as a duplicate. You can follow that ticket.

Comment by Roberto Pérez [ 11/May/23 ]

Please remove the How to Reproduce section in the Description since it is better described in the comments above

Comment by Roberto Pérez [ 11/May/23 ]

Output:

V2 - Description for license: 5555XXX
V2 - Deleted - Description for license: 5555XXX

V2 - Description for license: 5555XXX
V2 - Deleted - Description for license: 5555XXX

V3 - Description for license: 5555XXX
V3 - Deleted - Description for license: 5555XXX

V3 - Description for license: 5555XXX

Unhandled Exception: System.ArgumentException: ValueType 'Sample.Program+DeletedCar' of parameterSerializer does not match parameter type 'Sample.Program+Car'.
Parameter name: parameterSerializer
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToFilterTranslators.ExpressionToFilterTranslator.TranslateLambda(TranslationContext context, LambdaExpression lambdaExpression, IBsonSerializer parameterSerializer, Boolean asRoot)
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToPipelineTranslators.WhereMethodToPipelineTranslator.Translate(TranslationContext context, MethodCallExpression expression)
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToPipelineTranslators.ExpressionToPipelineTranslator.Translate(TranslationContext context, Expression expression)
   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.FirstMethodToExecutableQueryTranslator`1.Translate[TDocument](MongoQueryProvider`1 provider, TranslationContext context, MethodCallExpression expression)
   at MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToExecutableQueryTranslators.ExpressionToExecutableQueryTranslator.TranslateScalar[TDocument,TResult](MongoQueryProvider`1 provider, Expression expression)
   at MongoDB.Driver.Linq.Linq3Implementation.MongoQueryProvider`1.Execute[TResult](Expression expression)
   at System.Linq.Queryable.FirstOrDefault[TSource](IQueryable`1 source)
   at Sample.Program.GetCarDescription_Fails(IQueryable`1 queryable, String licensePlate) in D:\tfs2015\Shared\Packages\Panda.DataAccess\Sample\Program.cs:line 60
   at Sample.Program.Main(String[] args) in D:\tfs2015\Shared\Packages\Panda.DataAccess\Sample\Program.cs:line 47

Comment by Roberto Pérez [ 11/May/23 ]

    internal class Program
    {
        private static void Main(string[] args)
        {
            foreach (var linqProvider in new []{ LinqProvider.V2, LinqProvider.V3})
            {
                var builder = new MongoUrlBuilder
                {
                    DatabaseName = "Sample",
                    Server = new MongoServerAddress("localhost", 27017)
                };
                var mongoClientSettings = MongoClientSettings.FromUrl(builder.ToMongoUrl());
                mongoClientSettings.LinqProvider = linqProvider;
                var mongoClient = new MongoClient(mongoClientSettings);
                var mongoDatabase = mongoClient.GetDatabase(builder.DatabaseName);
 
                var licensePlate = "5555XXX";
 
                var carCollection = mongoDatabase.GetCollection<Car>("Cars");
                carCollection.DeleteMany(c => true);
                carCollection.InsertOne(new Car
                {
                    Id = licensePlate,
                    Description = $"{linqProvider} - Description for license: {licensePlate}"
                });
 
                var deletedCarCollection = mongoDatabase.GetCollection<DeletedCar>("DeletedCars");
                deletedCarCollection.DeleteMany(c => true);
                deletedCarCollection.InsertOne(new DeletedCar
                {
                    Id = licensePlate,
                    Description = $"{linqProvider} - Deleted - Description for license: {licensePlate}",
                    DeletedDate = DateTime.UtcNow.AddDays(-1)
                });
 
                Console.WriteLine(GetCarDescription_Works(carCollection.AsQueryable(), licensePlate));
                Console.WriteLine(GetCarDescription_Works(deletedCarCollection.AsQueryable(), licensePlate));
                Console.WriteLine();
                Console.WriteLine(GetCarDescription_Fails(carCollection.AsQueryable(), licensePlate));
                Console.WriteLine(GetCarDescription_Fails(deletedCarCollection.AsQueryable(), licensePlate));
                Console.WriteLine();
                Console.WriteLine();
            }
        }
 
        private static string GetCarDescription_Works<T>(IQueryable<T> queryable, string licensePlate) where T : Car
        {
            return queryable.Where(d => d.Id == licensePlate).Select(d => d.Description).FirstOrDefault();
        }
 
        private static string GetCarDescription_Fails(IQueryable<Car> queryable, string licensePlate)
        {
            return queryable.Where(d => d.Id == licensePlate).Select(d => d.Description).FirstOrDefault();
        }
 
        private class Car
        {
            public string Id { get; set; }
            public string Description { get; set; }
        }
 
        private class DeletedCar : Car
        {
            public DateTime DeletedDate { get; set; }
        }
    }

Comment by PM Bot [ 11/May/23 ]

Hi suikevil, thank you for reporting this issue! The team will look into it and get back to you soon.

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