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

Enum constant not serialized using the correct serializer

    • Type: Icon: Bug Bug
    • Resolution: Fixed
    • Priority: Icon: Major - P3 Major - P3
    • 2.16.1
    • Affects Version/s: None
    • Component/s: None
    • None

      Summary

      With the latest C# driver (2.15.1), when running an aggregate query that includes a projection step with a LINQ predicate, the predicate is compiled ignoring any of the custom serializers, resulting in an incorrect query.

      Visual Studio 2019

      .NET Core 3.1

      MongoDB.Driver 2.15.1

      How to Reproduce

      Consider the following program:

       

      class Program
          {
              static void Main(string[] args)
              {
                  var mongo = new MongoClient(new MongoUrl("mongodb://localhost:27017/local"));
                  var database = mongo.GetDatabase("local");
      
                  var findQuery = database.GetCollection<Order>("orders")
                      .Find(o => o.Items.Any(i => i.Type == ItemType.Refund));            Console.WriteLine(findQuery.ToString());
      
                  var query = database.GetCollection<Order>("orders")
                      .Aggregate()
                      .Project((o) => new
                      {
                          o.Id,
                          HasAnyRefund = o.Items.Any(i => i.Type == ItemType.Refund)
                      });            Console.WriteLine(query.ToString());
              }
          }
      
          public class Order
          {
              public int Id { get; set; }
              public List<Item> Items { get; set; }
          }
      
          public class Item
          {
              [BsonSerializer(typeof(CamelCaseEnumSerializer<ItemType>))]
              public ItemType Type { get; set; }
          }
      
          public enum ItemType
          {
              SaleItem,
              Refund
          }
      
          public class CamelCaseEnumSerializer<T> : EnumSerializer<T>
              where T : struct, Enum
          {
              private static string ToCamelCase(string s)
              {
                  return char.ToLowerInvariant(s[0]) + s.Substring(1);
              }
      
              public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, T value)
              {
                  context.Writer.WriteString(ToCamelCase(value.ToString()));
              }
      
              public override T Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
              {
                  return (T)Enum.Parse(typeof(T), context.Reader.ReadString(), true);
              }
          } 

      In the above example, a custom serializer is registered for the Enum type, which should be respected.  When the standard Find query is run, the output is:

      find({ "Items" : { "$elemMatch" : { "Type" : "refund" } } })

      however, when the Aggregate query is run, the output is:

      aggregate([{ "$project" : { "Id" : "$_id", "HasAnyRefund" : { "$anyElementTrue" : { "$map" : { "input" : "$Items", "as" : "i", "in" : { "$eq" : ["$$i.Type", 1] } } } }, "_id" : 0 } }])

      Clearly, the predicate in the projection is not being compiled with serializers and it's serializing ItemType.Refund as 1 (its Enum index) instead of "refund" (as per the serializer).

            Assignee:
            robert@mongodb.com Robert Stam
            Reporter:
            adam@pharmadata.com Adam Gilmore
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Resolved: