LINQ provider does not respect BsonIgnoreIfNull

XMLWordPrintableJSON

    • Type: Bug
    • Resolution: Works as Designed
    • Priority: Unknown
    • None
    • Affects Version/s: None
    • Component/s: None
    • None
    • None
    • Dotnet Drivers
    • 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?
    • None
    • None
    • None
    • None
    • None
    • None

      Summary

      When projecting nullable fields, the MongoDB .NET LINQ provider does not respect the [BsonIgnoreIfNull] attribute when building the query.

      This leads to an exception during deserialization:

      System.FormatException : Cannot deserialize a 'Guid' from BsonType 'Null'.
         at MongoDB.Bson.Serialization.Serializers.GuidSerializer.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
         at MongoDB.Bson.Serialization.IBsonSerializerExtensions.Deserialize[TValue](IBsonSerializer`1 serializer, BsonDeserializationContext context)
         at MongoDB.Driver.Linq.Linq3Implementation.Serializers.IEnumerableSerializerBase`2.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
         at MongoDB.Bson.Serialization.IBsonSerializerExtensions.Deserialize[TValue](IBsonSerializer`1 serializer, BsonDeserializationContext context)
         at MongoDB.Driver.Linq.Linq3Implementation.Serializers.WrappedValueSerializer`1.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
         at MongoDB.Bson.Serialization.IBsonSerializerExtensions.Deserialize[TValue](IBsonSerializer`1 serializer, BsonDeserializationContext context)
         at MongoDB.Driver.Core.Operations.CursorBatchDeserializationHelper.DeserializeBatch[TDocument](RawBsonArray batch, IBsonSerializer`1 documentSerializer, MessageEncoderSettings messageEncoderSettings)

       
      <PackageReference Include="MongoDB.Bson" Version="3.5.2" />
      <PackageReference Include="MongoDB.Driver" Version="3.5.2" />

      How to Reproduce

       

      [TestFixture]
      public class MongoCases_Linq3_ProjectWithNullableGuid
      {
          [Test]
          public async Task Test()
          {
              BsonSerializer.TryRegisterSerializer(new GuidSerializer(GuidRepresentation.CSharpLegacy));
      
              var mongoClientSettings = MongoClientSettings.FromConnectionString("mongodb://localhost:27017");
      
              var mongoClient = new MongoClient(mongoClientSettings);
      
              var db = mongoClient.GetDatabase(Guid.NewGuid().ToString()[..8]);
      
              var collection = db.GetCollection<User>("users");
      
              var user = new User
              {
                  Tasks =
                  [
                      new UserTask
                      {
                          Summary = "Task 1",
                          CustomerId = null
                      }
                  ]
              };
      
              await collection.InsertOneAsync(user);
      
              var query = collection
                  .Find(Builders<User>.Filter.Empty)
                  .Project(u => u.Tasks
                      .Where(t => t.CustomerId.HasValue)
                      .Select(t => t.CustomerId!.Value)
                  );
      
              var customerIds = (await query.FirstOrDefaultAsync()).ToArray();
      
              // System.FormatException : Cannot deserialize a 'Guid' from BsonType 'Null'.
              //     at MongoDB.Bson.Serialization.Serializers.GuidSerializer.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
              //     at MongoDB.Bson.Serialization.IBsonSerializerExtensions.Deserialize[TValue](IBsonSerializer`1 serializer, BsonDeserializationContext context)
              //     at MongoDB.Driver.Linq.Linq3Implementation.Serializers.IEnumerableSerializerBase`2.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
              //     at MongoDB.Bson.Serialization.IBsonSerializerExtensions.Deserialize[TValue](IBsonSerializer`1 serializer, BsonDeserializationContext context)
              //     at MongoDB.Driver.Linq.Linq3Implementation.Serializers.WrappedValueSerializer`1.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
              //     at MongoDB.Bson.Serialization.IBsonSerializerExtensions.Deserialize[TValue](IBsonSerializer`1 serializer, BsonDeserializationContext context)
              //     at MongoDB.Driver.Core.Operations.CursorBatchDeserializationHelper.DeserializeBatch[TDocument](RawBsonArray batch, IBsonSerializer`1 documentSerializer, MessageEncoderSettings messageEncoderSettings)
              //     at MongoDB.Driver.Core.Operations.FindOperation`1.CreateFirstCursorBatch(BsonDocument cursorDocument)
              //     at MongoDB.Driver.Core.Operations.FindOperation`1.CreateCursor(IChannelSourceHandle channelSource, IChannelHandle channel, BsonDocument commandResult)
              //     at MongoDB.Driver.Core.Operations.FindOperation`1.ExecuteAsync(OperationContext operationContext, RetryableReadContext context)
              //     at MongoDB.Driver.Core.Operations.FindOperation`1.ExecuteAsync(OperationContext operationContext, IReadBinding binding)
              //     at MongoDB.Driver.OperationExecutor.ExecuteReadOperationAsync[TResult](OperationContext operationContext, IClientSessionHandle session, IReadOperation`1 operation, ReadPreference readPreference, Boolean allowChannelPinning)
              //     at MongoDB.Driver.MongoCollectionImpl`1.ExecuteReadOperationAsync[TResult](IClientSessionHandle session, IReadOperation`1 operation, ReadPreference explicitReadPreference, Nullable`1 timeout, CancellationToken cancellationToken)
              //     at MongoDB.Driver.MongoCollectionImpl`1.FindAsync[TProjection](FilterDefinition`1 filter, FindOptions`2 options, CancellationToken cancellationToken)
              //     at MongoDB.Driver.IAsyncCursorSourceExtensions.FirstOrDefaultAsync[TDocument](IAsyncCursorSource`1 source, CancellationToken cancellationToken)
      
              Assert.That(customerIds.Length, Is.EqualTo(0));
          }
      
          class User
          {
              [BsonId]
              public Guid Id { get; set; }
      
              [BsonElement("tasks")]
              public IReadOnlyCollection<UserTask> Tasks { get; set; }
          }
      
          class UserTask
          {
              [BsonElement("summary")]
              public string Summary { get; set; }
      
              [BsonElement("customerId"), BsonIgnoreIfNull]
              public Guid? CustomerId { get; set; }
          }
      }

       

      # {
      #     "_id" : CSUUID("F906C958-92B7-4C2D-AC73-2D1F90190236"),
      #     "tasks" : [
      #         {
      #             "summary" : "Task 1"
      #         }
      #     ]
      # }
      
      db.getCollection("users").find(
          { }, 
          { 
              "_v" : { 
                  "$map" : { 
                      "input" : { 
                          "$filter" : { 
                              "input" : "$tasks", 
                              "as" : "t", 
                              "cond" : { "$ne" : ["$$t.customerId", null] } 
                          } 
                      }, 
                      "as" : "t", 
                      "in" : "$$t.customerId" 
                  } 
              }, 
              "_id" : 0 
          }
      )
      
      # {
      #     "_v" : [
      #         null
      #     ]
      # }

      Additional Background

      Please provide any additional background information that may be helpful in diagnosing the bug.

            Assignee:
            Robert Stam (Inactive)
            Reporter:
            flibustier seas
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: