Uploaded image for project: 'C# Driver'
  1. C# Driver
  2. CSHARP-1907

Type discriminators don't work when collection document type is an interface

    • Type: Icon: Bug Bug
    • Resolution: Unresolved
    • Priority: Icon: Major - P3 Major - P3
    • None
    • Affects Version/s: None
    • Component/s: Serialization
    • None
    • Hide

      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?

      Show
      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?

      When the T of a collection is an interface, the type discriminators do not get added properly to a query. One of two things happens depending on how you query them

      1. The type discriminator isn't added at all
      2. The type discriminator added is incorrect.

      The _t for each document in the database is correctly serialized, this appears to only be an issue for reading.

      Reproduction script:

      Reproduction
      async Task Main()
      {
      	var client = new MongoClient();
      	var db = client.GetDatabase("polymorphismTest");
      	var col = db.GetCollection<IFoo>("iFoo");
      	
      	// Clean up any existing documents
      	await col.DeleteManyAsync(Builders<IFoo>.Filter.Empty);
      	
      	// Insert 2 new test documents of different types, each implementing IFoo
      	await col.InsertOneAsync(new Widget1() { Id = ObjectId.GenerateNewId(), SomeField = "ABC", Bar = 10 });
      	await col.InsertOneAsync(new Widget2() { Id = ObjectId.GenerateNewId(), SomeField = "ABC", Bar = 10M });
      	
      	// Build a query using .OfType<> on the collection.
      	var widget1QueryColOfType = col.OfType<Widget1>().Find(Builders<Widget1>.Filter.Eq(x => x.SomeField, "ABC"));
      	var widget2QueryColOfType = col.OfType<Widget2>().Find(Builders<Widget2>.Filter.Eq(x => x.SomeField, "ABC"));
      	Console.WriteLine("OfType<> on the Collection");
      	Console.WriteLine(widget1QueryColOfType.ToString());
      	Console.WriteLine(widget2QueryColOfType.ToString());
      	Console.WriteLine();
      	
      	// Build a query using .OfType<> on the Builder to change from IFoo to the concrete type.
      	var widget1QueryBuilderOfType = col.Find(Builders<IFoo>.Filter.OfType<Widget1>(Builders<Widget1>.Filter.Eq(x => x.SomeField, "ABC")));
      	var widget2QueryBuilderOfType = col.Find(Builders<IFoo>.Filter.OfType<Widget2>(Builders<Widget2>.Filter.Eq(x => x.SomeField, "ABC")));
      	Console.WriteLine("OfType<> on the Builder");
      	Console.WriteLine(widget1QueryBuilderOfType.ToString());
      	Console.WriteLine(widget2QueryBuilderOfType.ToString());
      	Console.WriteLine();
      	
      	Console.WriteLine("Documents in the database");
      	var rawDocsInDatabase = await db.GetCollection<BsonDocument>("iFoo").Find(Builders<BsonDocument>.Filter.Empty).ToListAsync();
      	foreach(var doc in rawDocsInDatabase)
      		Console.WriteLine(doc.ToJson());
      }
      
      public interface IFoo
      {
      	ObjectId Id { get; set;}
      	string SomeField { get; set;}
      }
      
      public class Widget1 : IFoo
      {
      	public ObjectId Id {get;set;}
      	public string SomeField { get; set; }
      	public int Bar { get; set; }
      }
      
      public class Widget2 : IFoo
      {
      	public ObjectId Id {get;set;}
      	public string SomeField { get; set; }
      	public Decimal Bar { get; set; } 
      }
      
      Output
      OfType<> on the Collection
      find({ "SomeField" : "ABC" })
      find({ "SomeField" : "ABC" })
      
      OfType<> on the Builder
      find({ "_t" : "UserQuery+Widget1, LINQPadQuery", "SomeField" : "ABC" })
      find({ "_t" : "UserQuery+Widget2, LINQPadQuery", "SomeField" : "ABC" })
      
      Documents in the database
      { "_id" : ObjectId("589347de303cd5d0ca4540e4"), "_t" : "Widget1", "SomeField" : "ABC", "Bar" : 10 }
      { "_id" : ObjectId("589347de303cd5d0ca4540e6"), "_t" : "Widget2", "SomeField" : "ABC", "Bar" : "10" }
      

            Assignee:
            ferdinando.papale@mongodb.com Ferdinando Papale
            Reporter:
            peter.garafano@mongodb.com Peter Garafano (Inactive)
            Votes:
            2 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated: