From d45424e62af33812411274cc754f2a92ab538295 Mon Sep 17 00:00:00 2001 From: rstam Date: Wed, 1 Oct 2025 10:30:30 -0700 Subject: [PATCH] CSHARP-5748: Use KeyValuePairSerializer consistently for KeyValuePair --- .../Serializers/KeyValuePairSerializer.cs | 24 +++++++++++++ ...essionToAggregationExpressionTranslator.cs | 35 +++++-------------- .../Jira/CSharp1326Tests.cs | 2 +- ...nToAggregationExpressionTranslatorTests.cs | 4 +-- 4 files changed, 35 insertions(+), 30 deletions(-) diff --git a/src/MongoDB.Bson/Serialization/Serializers/KeyValuePairSerializer.cs b/src/MongoDB.Bson/Serialization/Serializers/KeyValuePairSerializer.cs index ea1f59ac971..1ff39685b2a 100644 --- a/src/MongoDB.Bson/Serialization/Serializers/KeyValuePairSerializer.cs +++ b/src/MongoDB.Bson/Serialization/Serializers/KeyValuePairSerializer.cs @@ -29,6 +29,30 @@ public interface IKeyValuePairSerializer BsonType Representation { get; } } + /// + /// Static factory class for KeyValuePairSerializers. + /// + public static class KeyValuePairSerializer + { + /// + /// Creates a KeyValuePairSerializer. + /// + /// The representation. + /// The key serializer. + /// The value Serializer. + /// A KeyValuePairSerializer. + public static IBsonSerializer Create( + BsonType representation, + IBsonSerializer keySerializer, + IBsonSerializer valueSerializer) + { + var keyType = keySerializer.ValueType; + var valueType = valueSerializer.ValueType; + var keyValuePairSerializerType = typeof(KeyValuePairSerializer<,>).MakeGenericType(keyType, valueType); + return (IBsonSerializer)Activator.CreateInstance(keyValuePairSerializerType, [representation, keySerializer, valueSerializer]); + } + } + /// /// Represents a serializer for KeyValuePairs. /// diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/NewKeyValuePairExpressionToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/NewKeyValuePairExpressionToAggregationExpressionTranslator.cs index b2388206503..cfe4f67f6a8 100644 --- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/NewKeyValuePairExpressionToAggregationExpressionTranslator.cs +++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/NewKeyValuePairExpressionToAggregationExpressionTranslator.cs @@ -16,7 +16,9 @@ using System; using System.Collections.Generic; using System.Linq.Expressions; +using MongoDB.Bson; using MongoDB.Bson.Serialization; +using MongoDB.Bson.Serialization.Serializers; using MongoDB.Driver.Linq.Linq3Implementation.Ast.Expressions; namespace MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators @@ -43,37 +45,16 @@ public static TranslatedExpression Translate( var keyTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, keyExpression); var valueTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, valueExpression); - var serializer = CreateResultSerializer(expression.Type, keyTranslation.Serializer, valueTranslation.Serializer, out var keyElementName, out var valueElementName); var ast = AstExpression.ComputedDocument([ - AstExpression.ComputedField(keyElementName, keyTranslation.Ast), - AstExpression.ComputedField(valueElementName, valueTranslation.Ast) + AstExpression.ComputedField("k", keyTranslation.Ast), + AstExpression.ComputedField("v", valueTranslation.Ast) ]); - return new TranslatedExpression(expression, ast, serializer); - } - - private static IBsonSerializer CreateResultSerializer( - Type resultType, - IBsonSerializer keySerializer, - IBsonSerializer valueSerializer, - out string keyElementName, - out string valueElementName) - { - var constructorInfo = resultType.GetConstructor([keySerializer.ValueType, valueSerializer.ValueType]); - var classMap = new BsonClassMap(resultType); - classMap.MapConstructor(constructorInfo); - classMap.AutoMap(); - var keyMemberMap = classMap.GetMemberMap("Key"); - keyElementName = keyMemberMap.ElementName; - keyMemberMap.SetSerializer(keySerializer); - var valueMemberMap = classMap.GetMemberMap("Value"); - valueElementName = valueMemberMap.ElementName; - valueMemberMap.SetSerializer(valueSerializer); - classMap.Freeze(); + var keySerializer = keyTranslation.Serializer; + var valueSerializer = valueTranslation.Serializer; + var keyValuePairSerializer = KeyValuePairSerializer.Create(BsonType.Document, keySerializer, valueSerializer); - // have to use BsonClassMapSerializer here to mimic the MemberInitExpressionToAggregationExpressionTranslator to avoid risking a behavioral breaking change - var serializerType = typeof(BsonClassMapSerializer<>).MakeGenericType(resultType); - return (IBsonSerializer)Activator.CreateInstance(serializerType, classMap); + return new TranslatedExpression(expression, ast, keyValuePairSerializer); } } } diff --git a/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp1326Tests.cs b/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp1326Tests.cs index 4d30844b780..4dc04e29b93 100644 --- a/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp1326Tests.cs +++ b/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Jira/CSharp1326Tests.cs @@ -49,7 +49,7 @@ public void Projection_of_ArrayOfDocuments_dictionary_keys_and_values_should_wor stages, "{ $match : { ParentId : { $in : [1, 2, 3] }, Gender : 'Male' } }", "{ $group : { _id : '$ParentId', _elements : { $push : '$$ROOT' } } }", - "{ $project : { Key : '$_id', Value : '$_elements', _id : 0 } }"); + "{ $project : { k : '$_id', v : '$_elements', _id : 0 } }"); var results = aggregate.ToList().OrderBy(x => x.Key).ToList(); results[0].Key.Should().Be(1); diff --git a/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/NewKeyValuePairExpressionToAggregationExpressionTranslatorTests.cs b/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/NewKeyValuePairExpressionToAggregationExpressionTranslatorTests.cs index 68d571ab9b0..46575fe696d 100644 --- a/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/NewKeyValuePairExpressionToAggregationExpressionTranslatorTests.cs +++ b/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/NewKeyValuePairExpressionToAggregationExpressionTranslatorTests.cs @@ -37,7 +37,7 @@ public void NewKeyValuePair_should_translate() .Select(d => new KeyValuePair("X", d.X)); var stages = Translate(collection, queryable); - AssertStages(stages, "{ $project : { Key : 'X', Value : '$X', _id : 0 } }"); + AssertStages(stages, "{ $project : { k : 'X', v : '$X', _id : 0 } }"); var result = queryable.Single(); result.Key.Should().Be("X"); @@ -54,7 +54,7 @@ public void KeyValuePair_Create_should_translate() .Select(d => KeyValuePair.Create("X", d.X)); var stages = Translate(collection, queryable); - AssertStages(stages, "{ $project : { Key : 'X', Value : '$X', _id : 0 } }"); + AssertStages(stages, "{ $project : { k : 'X', v : '$X', _id : 0 } }"); var result = queryable.Single(); result.Key.Should().Be("X");