-
Type:
Bug
-
Resolution: Works as Designed
-
Priority:
Unknown
-
None
-
Affects Version/s: None
-
Component/s: None
-
None
-
None
-
Dotnet Drivers
-
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.
- related to
-
CSHARP-5860 Consider whether the LINQ provider should generate different MQL if it can detect that a field might be missing
-
- Backlog
-