[CSHARP-2816] Exception when querying via interface class Created: 23/Oct/19  Updated: 31/Mar/22

Status: Backlog
Project: C# Driver
Component/s: Serialization
Affects Version/s: 2.9.2
Fix Version/s: None

Type: Bug Priority: Major - P3
Reporter: Jevon Kendon Assignee: Unassigned
Resolution: Unresolved Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Windows



 Description   

Even though this issue is closely related to CSHARP-485, consider this small unit-test.

using System;
using System.Threading.Tasks;
using Mongo2Go;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Conventions;
using MongoDB.Driver;
using Xunit;namespace IntegrationTest
{
    public class MongoTestHelper : IDisposable
    {
        private readonly MongoDbRunner _runner;
        private readonly IMongoDatabase _db;                                        public MongoTestHelper(string databaseName, bool debug = false)
        {
            if (debug)
            {
                _runner = MongoDbRunner.StartForDebugging();
            }
            else
            {
                _runner = MongoDbRunner.Start();
            }                                   var mongo = new MongoClient(_runner.ConnectionString);
            _db = mongo.GetDatabase(databaseName);
        }                public IMongoDatabase GetDatabase()
        {
            return _db;
        }                public void Dispose()
        {
            _runner.Dispose();
        }
    }        public class AnimalTests : IDisposable
    {
        private readonly MongoTestHelper _helper;                        public AnimalTests()
        {
            var conventionPack = new ConventionPack
            {
                new IgnoreExtraElementsConvention(true)
            };
            ConventionRegistry.Register("IgnoreExtraElements", conventionPack, type => true);                     BsonClassMap.RegisterClassMap<Dog>();
            BsonClassMap.RegisterClassMap<Cat>();
            // var dogSerializer = BsonSerializer.LookupSerializer<Dog>();
            // BsonSerializer.RegisterSerializer<IAnimal>(new ImpliedImplementationInterfaceSerializer<IAnimal, Dog>(dogSerializer));
            //
            // var catSerializer = BsonSerializer.LookupSerializer<Cat>();
            // BsonSerializer.RegisterSerializer<IAnimal>(new ImpliedImplementationInterfaceSerializer<IAnimal, Cat>(catSerializer));
            //
            // because:
            //   MongoDB.Bson.BsonSerializationException : There is already a serializer registered for type IAnimal.
            _helper = new MongoTestHelper("db_test", true);
        }               [Fact]
        public async Task Some_Test()
        {
            var animals = new IAnimal[]
            {
                new Dog(), 
                new Cat()
            };                        var db = _helper.GetDatabase();
            db.DropCollection("animal");
            var collWrite = db.GetCollection<IAnimal>("animal");
            
            collWrite.InsertMany(animals);                        var collRead = db.GetCollection<IAnimal>("animal");            // THIS WORKS
            await (await collRead.FindAsync(x => true)).ToListAsync();            // THIS DOESN'T
            await (await collRead.FindAsync(x => x.Type == "dog")).ToListAsync();
        }                public void Dispose()
        {
            _helper.Dispose();
        }                    public interface IAnimal
        {
            string Type { get; set; }
            string Speak { get; set; }
        }                public class Dog : IAnimal
        {
            public string Type { get; set; }
            public string Speak { get; set; }            public Dog()
            {
                Type = "dog";
                Speak = "woof";
            }
        }                public class Cat : IAnimal
        {
            public string Type { get; set; }
            public string Speak { get; set; }            public Cat()
            {
                Type = "cat";
                Speak = "meow";
            }
        }
    }
} 

It fails with error:

Message: 
    System.InvalidOperationException : {document}.Type is not supported.
  Stack Trace: 
    PredicateTranslator.GetFieldExpression(Expression expression)
    PredicateTranslator.TranslateComparison(Expression variableExpression, ExpressionType operatorType, ConstantExpression constantExpression)
    PredicateTranslator.Translate(Expression node)
    PredicateTranslator.Translate(Expression node, IBsonSerializerRegistry serializerRegistry)
    MongoCollectionImpl`1.CreateFindOperation[TProjection](FilterDefinition`1 filter, FindOptions`2 options)
    MongoCollectionImpl`1.FindAsync[TProjection](IClientSessionHandle session, FilterDefinition`1 filter, FindOptions`2 options, CancellationToken cancellationToken)
    <>c__DisplayClass43_0`1.<FindAsync>b__0(IClientSessionHandle session)
    MongoCollectionImpl`1.UsingImplicitSessionAsync[TResult](Func`2 funcAsync, CancellationToken cancellationToken)
    AnimalTests.Some_Test() line 92
    --- End of stack trace from previous location where exception was thrown --- 

The difference is two concrete classes that use interface IAnimal. For that reason, I can't use the explicit serializer registration.

Though this example is contrived, it reflects a real world problem I was hoping to solve.

In the meantime, I've had to resort to a plan BSON search:

var filter = new BsonDocument {{"Type", "dog"}}; 

 



 Comments   
Comment by Jevon Kendon [ 23/Oct/19 ]

Sorry, I'm unable to clean it up after posting. No edit ability.

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