Dictionnaire -to-BsonDocument conversion en omettant le champ _t

J’utilise la méthode d’extension ToBsonDocument de MongoDB.Bson pour convertir ce dictionnaire:

  var dictionary = new Dictionary {{"person", new Dictionary {{"name", "John"}}}}; var document = dictionary.ToBsonDocument(); 

Et voici le document résultant:

  { "person" : { "_t" : "System.Collections.Generic.Dictionary`2[System.Ssortingng,System.Object]", "_v" : { "name" : "John" } } } 

Existe-t-il un moyen de se débarrasser de ces fichiers _t / _v? Je voudrais que le document résultant ressemble à ceci:

  { "person" : { "name" : "John" } } 

UPD: J’ai trouvé le code dans DictionaryGenericSerializer:

 if (nominalType == typeof(object)) { var actualType = value.GetType(); bsonWriter.WriteStartDocument(); bsonWriter.WriteSsortingng("_t", TypeNameDiscriminator.GetDiscriminator(actualType)); bsonWriter.WriteName("_v"); Serialize(bsonWriter, actualType, value, options); // recursive call replacing nominalType with actualType bsonWriter.WriteEndDocument(); return; } 

Il semble donc qu’il n’y ait pas trop d’options avec ce sérialiseur lorsque le type de valeur est object .

Vous devez tout d’abord sérialiser en JSON, puis en BSON,

 var jsonDoc = Newtonsoft.Json.JsonConvert.SerializeObject(dictionary); var bsonDoc = MongoDB.Bson.Serialization.BsonSerializer.Deserialize(jsonDoc); 

Cela est dû au fait que vous spécifiez le type d’ object pour les valeurs du dictionnaire mais que vous utilisez en fait le type Dictionary pour la valeur d’enregistrement particulière. Par conséquent, le pilote CSharp enregistre le nom complet du type concret pour désérialiser correctement ce document à l’avenir. Vous pouvez également en savoir plus à ce sujet ici: Sérialiser des documents avec le pilote CSharp: Classes polymorphes et discriminateurs

Pour obtenir le résultat souhaité, vous devez spécifier un type concret pour les valeurs du dictionnaire:

 var dictionary = new Dictionary> { { "person", new Dictionary { { "name", "John" } } } }; var document = dictionary.ToBsonDocument(); 

Une conversion directe d’object en BSON est difficile.

Au lieu d’aller d’object -> Json -> Bson

 // Object --> JSON using System.Web.Extensions; using System.Web; using System.Web.Script.Serialization; JavaScriptSerializer js = new JavaScriptSerializer(); ssortingng json = js.Serialize(poco); // poco is ur class object //JSON --> BSON MongoDB.Bson.BsonDocument document = MongoDB.Bson.Serialization.BsonSerializer.Deserialize(json); 

Passer des objects .NET à JSON vers BSON, tout en évitant le codage _t / _v, entraînera une perte d’informations de type pour les dates et d’autres types spécifiques à BSON.

La solution que j’ai trouvée pour éviter _t / _v tout en préservant les types BSON consistait à enregistrer un sérialiseur de valeurs personnalisé pour DictionaryInterfaceImplementerSerializer intégré du pilote (et éventuellement, EnumerableInterfaceImplementerSerializer ). J’ai testé la solution pour la génération «Extended JSON», c’est-à-dire JSON avec une syntaxe spéciale pour les types spécifiques à BSON, mais le principe devrait être le même pour la sortie directe BSON.

Pour ce faire, commencez par copier ObjectSerializer standard dans votre projet C # (et renommez-le pour éviter toute ambiguïté): https://github.com/mongodb/mongo-csharp-driver/blob/master/src/MongoDB.Bson/Serialization/ Sérialiseurs / ObjectSerializer.cs

Outre la private void SerializeDiscriminatedValue(BsonSerializationContext context, BsonSerializationArgs args, object value, Type actualType) du nom de la classe, la private void SerializeDiscriminatedValue(BsonSerializationContext context, BsonSerializationArgs args, object value, Type actualType) doit également être modifiée. (Dans mon cas, je souhaitais également éviter l’encodage _t / _v pour IEnumerable , ce qui est présenté ci-dessous.)

  private void SerializeDiscriminatedValue(BsonSerializationContext context, BsonSerializationArgs args, object value, Type actualType) { var serializer = BsonSerializer.LookupSerializer(actualType); var polymorphicSerializer = serializer as IBsonPolymorphicSerializer; // Added line var assignableToDictionaryOrEnumerable = typeof(IDictionary).IsAssignableFrom(actualType) || typeof(IEnumerable).IsAssignableFrom(actualType); if (polymorphicSerializer != null && polymorphicSerializer.IsDiscriminatorCompatibleWithObjectSerializer) { serializer.Serialize(context, args, value); } else { // Edited line if (assignableToDictionaryOrEnumerable || (context.IsDynamicType != null && context.IsDynamicType(value.GetType()))) { // We want this code to be executed for types that should be serialized without _t and _v fields args.NominalType = actualType; serializer.Serialize(context, args, value); } else { var bsonWriter = context.Writer; var discriminator = _discriminatorConvention.GetDiscriminator(typeof(object), actualType); bsonWriter.WriteStartDocument(); bsonWriter.WriteName(_discriminatorConvention.ElementName); BsonValueSerializer.Instance.Serialize(context, discriminator); bsonWriter.WriteName("_v"); serializer.Serialize(context, value); bsonWriter.WriteEndDocument(); } } } 

En supposant que le nom de la classe copiée et modifiée soit DynamicValueSerializer , utilisez le code suivant pour l’enregistrer en tant que sérialiseur de valeur au démarrage de l’application.

 BsonSerializer.RegisterSerializer(typeof(Dictionary), new DictionaryInterfaceImplementerSerializer, ssortingng, object>( DictionaryRepresentation.Document, new SsortingngSerializer(), new DynamicValueSerializer())); 

Veuillez noter que cela doit être fait pour chaque type réel, dont les valeurs doivent être utilisées. L’enregistrement du sérialiseur ne peut pas être effectué pour les interfaces. Ainsi, si SortedDictionary ou SortedList doivent être traités de la même manière que Dictionary , l’enregistrement doit être répété pour ces types. (Cela détermine si les dictionnaires contenus en tant que valeurs dans des collections de ces types seront sérialisés sans _t / _v, et pas nécessairement si les objects de ces types eux-mêmes seront sérialisés de cette manière.)

Pour appliquer le même principe de sérialisation aux objects List , utilisez le code d’enregistrement suivant.

 BsonSerializer.RegisterSerializer(typeof(List), new EnumerableInterfaceImplementerSerializer, object>( new DynamicValueSerializer()));