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

Update.Set can generate invalid $set when type of value does not match type of POCO

    • Type: Icon: Bug Bug
    • Resolution: Fixed
    • Priority: Icon: Critical - P2 Critical - P2
    • 2.8.0
    • Affects Version/s: 2.5
    • Component/s: API
    • None
    • Fully Compatible

      When the value provided to Update.Set does not match the type of the underlying property we attempt to convert the value to an instance of the type of the underlying property.

      This process sometimes results in an invalid $set update operator.

      Here's one repro, where the underlying property is of type List<string> and the value provided is of type BsonArray:

      public class C
      {
          public List<string> L { get; set; }
      }
      
      public static class Program
      {
          public static void Main(string[] args)
          {
              var value = new BsonArray { "one", "two", "three" };
              var update = Builders<C>.Update.Set(nameof(C.L), value);
      
              var serializerRegistry = BsonSerializer.SerializerRegistry;
              var documentSerializer = serializerRegistry.GetSerializer<C>();
              var rendered = update.Render(documentSerializer, serializerRegistry).ToJson();
              Console.WriteLine(rendered);
          }
      }
      

      The resulting update specification is:

      { "$set" : { "L" : "[one, two, three]" } }
      

      which is incorrect (note that the value of L is a string, not an array of strings).

      In the original description below this invalid update then subsequently resulted in a deserialization error.

      Original description below:

      I am encountering an odd deserialization error while using the newest version of the c# driver. Updates to a List<string> with a BsonArray seem to causes the write to be performed incorrectly. I wrote a sample program to demonstrate this. I should have a field with an array of strings. Instead of ending up with a document that looks like this:

      { "_id" : "4a82b074-c9d2-4507-b762-4b32ebbf88be", "Strings" : [ "seven", "eight", "nine" ] }

      I get one that looks like this:

      { "_id" : "4a82b074-c9d2-4507-b762-4b32ebbf88be", "Strings" : "[seven, eight, nine]" }

      Here's my sample application that will reproduce the error:

      using System;
      
      namespace ConsoleApp2
      {
          using System.Collections.Generic;
      
          using MongoDB.Bson;
          using MongoDB.Bson.Serialization.Attributes;
          using MongoDB.Driver;
      
          class Program
          {
              static void Main(string[] args)
              {
                  var collection = GetConnection();
      
                  // create record
                  var entity = new TestEntity()
                               {
                                   EntityId = System.Guid.NewGuid()
                                                    .ToString(),
                                   Strings = new List<string>()
                                             {
                                                 "one",
                                                 "two",
                                                 "three"
                                             }
                               };
      
                  collection.InsertOne(entity);
                  var found = collection.Find(Builders<TestEntity>.Filter.Eq(e => e.EntityId, entity.EntityId)).FirstOrDefault();
                  Console.WriteLine($"On Insert {string.Join(",", found.Strings)}");
      
                  // update
                  var update = Builders<TestEntity>.Update.Set(
                                                               e => e.Strings,
                                                               new List<string>()
                                                               {
                                                                   "four",
                                                                   "five",
                                                                   "six"
                                                               });
      
                  collection.UpdateOne(e => e.EntityId == entity.EntityId, update);
                  found = collection.Find(Builders<TestEntity>.Filter.Eq(e => e.EntityId, entity.EntityId)).FirstOrDefault();
                  Console.WriteLine($"After update {string.Join(",", found.Strings)}");
      
                  // try doing the update with a bsonarray
                  var a = new BsonArray();
                  a.Add(BsonValue.Create("seven"));
                  a.Add(BsonValue.Create("eight"));
                  a.Add(BsonValue.Create("nine"));
                  update = Builders<TestEntity>.Update.Set(nameof(TestEntity.Strings), a);
                  collection.UpdateOne(e => e.EntityId == entity.EntityId, update);
                  found = collection.Find(Builders<TestEntity>.Filter.Eq(e => e.EntityId, entity.EntityId)).FirstOrDefault();
                  Console.WriteLine($"After array update {string.Join(",", found.Strings)}");
              }
      
              public static IMongoCollection<TestEntity> GetConnection()
              {
                  var client = new MongoClient("mongodb://localhost:27017");
                  var database = client.GetDatabase("unittest");
                  return database.GetCollection<TestEntity>("driverunittest");
              }
          }
      
          public class TestEntity
          {
              [BsonId]
              public string EntityId { get; set; }
      
              public List<string> Strings { get; set; }
          }
      }
      

            Assignee:
            robert@mongodb.com Robert Stam
            Reporter:
            jpf478@snagajob.com Jason Ford
            Votes:
            0 Vote for this issue
            Watchers:
            6 Start watching this issue

              Created:
              Updated:
              Resolved: