字典 -to-BsonDocument转换省略_t字段
我正在使用ToBsonDocument
扩展方法来转换这个字典:
var dictionary = new Dictionary {{"person", new Dictionary {{"name", "John"}}}}; var document = dictionary.ToBsonDocument();
这是结果文件:
{ "person" : { "_t" : "System.Collections.Generic.Dictionary`2[System.String,System.Object]", "_v" : { "name" : "John" } } }
有没有办法摆脱这些_t / _v的东西? 我希望生成的文档看起来像这样:
{ "person" : { "name" : "John" } }
UPD:我在DictionaryGenericSerializer中找到了代码:
if (nominalType == typeof(object)) { var actualType = value.GetType(); bsonWriter.WriteStartDocument(); bsonWriter.WriteString("_t", TypeNameDiscriminator.GetDiscriminator(actualType)); bsonWriter.WriteName("_v"); Serialize(bsonWriter, actualType, value, options); // recursive call replacing nominalType with actualType bsonWriter.WriteEndDocument(); return; }
因此,当值类型为object
时,似乎没有太多选项可用于此序列化程序。
您应首先序列化为JSON,然后序列化为BSON,
var jsonDoc = Newtonsoft.Json.JsonConvert.SerializeObject(dictionary); var bsonDoc = MongoDB.Bson.Serialization.BsonSerializer.Deserialize(jsonDoc);
这是因为您为字典值指定了object
类型,但实际上对特定记录值使用了Dictionary
类型。 因此,CSharp驱动程序将保存具体类型的全名,以便将来正确反序列化此文档。 您还可以在此处阅读更多相关信息: 使用CSharp驱动程序序列化文档:多态类和鉴别器
要获得所需的结果,您应该为字典值指定具体类型:
var dictionary = new Dictionary> { { "person", new Dictionary { { "name", "John" } } } }; var document = dictionary.ToBsonDocument();
从物体到BSON的直接转换是困难的。
而是从对象– > Json – > Bson
// Object --> JSON using System.Web.Extensions; using System.Web; using System.Web.Script.Serialization; JavaScriptSerializer js = new JavaScriptSerializer(); string json = js.Serialize(poco); // poco is ur class object //JSON --> BSON MongoDB.Bson.BsonDocument document = MongoDB.Bson.Serialization.BsonSerializer.Deserialize(json);
从.NET对象到JSON再到BSON,同时避免_t / _v编码,将导致日期和其他BSON特定类型的类型信息丢失。
我发现在保留BSON类型的同时避免_t / _v的解决方案是为驱动程序的内置DictionaryInterfaceImplementerSerializer
(以及可选的EnumerableInterfaceImplementerSerializer
)注册自定义值序列化程序。 我已经测试了“扩展JSON”生成的解决方案,即具有BSON特定类型的特殊语法的JSON,但直接BSON输出的原理应该相同。
为此,首先将标准ObjectSerializer
复制到C#项目中(并重命名以避免歧义): https : //github.com/mongodb/mongo-csharp-driver/blob/master/src/MongoDB.Bson/Serialization/串行器/ ObjectSerializer.cs
除了类重命名之外,还需要编辑private void SerializeDiscriminatedValue(BsonSerializationContext context, BsonSerializationArgs args, object value, Type actualType)
方法。 (在我的例子中,我也想避免IEnumerable
_t / _v编码,这反映在下面。)
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
假设复制和编辑的类的名称是DynamicValueSerializer
,请使用以下代码在应用程序启动时将其注册为值序列化程序。
BsonSerializer.RegisterSerializer(typeof(Dictionary), new DictionaryInterfaceImplementerSerializer, string, object>( DictionaryRepresentation.Document, new StringSerializer(), new DynamicValueSerializer()));
请注意,必须为每个实际类型执行此操作,应使用其值。 无法对接口进行序列化程序注册。 因此,如果SortedDictionary
或SortedList
将以与Dictionary
相同的方式处理,则需要对这些类型重复注册。 (这会影响这些类型的集合中包含的字典是否将在没有_t / _v的情况下序列化,不一定是这些类型的对象本身是否会以这种方式序列化。)
要将相同的序列化原则应用于List
对象,请使用以下注册码。
BsonSerializer.RegisterSerializer(typeof(List