我正在使用ToBsonDocument
中的MongoDB.Bson
扩展程序来转换此词典:
var dictionary = new Dictionary<string, object> {{"person", new Dictionary<string, object> {{"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
时,似乎此序列化程序没有太多选项。
答案 0 :(得分:13)
您应首先序列化为JSON,然后序列化为BSON,
var jsonDoc = Newtonsoft.Json.JsonConvert.SerializeObject(dictionary);
var bsonDoc = MongoDB.Bson.Serialization.BsonSerializer.Deserialize<BsonDocument>(jsonDoc);
答案 1 :(得分:4)
这是因为您为字典值指定了object
类型,但实际上对特定记录值使用Dictionary<string, object>
类型。因此,CSharp驱动程序将保存具体类型的全名,以便将来正确反序列化此文档。您还可以在此处详细了解:Serialize Documents with the CSharp Driver: Polymorphic Classes and Discriminators
要获得所需的结果,您应该为字典值指定具体类型:
var dictionary = new Dictionary<string, Dictionary<string, object>>
{
{ "person", new Dictionary<string, object> { { "name", "John" } } }
};
var document = dictionary.ToBsonDocument();
答案 2 :(得分:2)
从对象到BSON的直接转换很困难。
取而代之的是对象 - &gt; Json - &gt; 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<BsonDocument>(json);
答案 3 :(得分:2)
从.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/Serializers/ObjectSerializer.cs
除了重命名类之外,还需要编辑private void SerializeDiscriminatedValue(BsonSerializationContext context, BsonSerializationArgs args, object value, Type actualType)
方法。 (在我的情况下,我也想避免IEnumerable<object>
的_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<string, object>).IsAssignableFrom(actualType) || typeof(IEnumerable<object>).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();
}
}
}
假设复制和编辑的类的名称为DynamicValueSerializer
,请在应用程序启动时使用以下代码将其注册为值序列化程序。
BsonSerializer.RegisterSerializer(typeof(Dictionary<string, object>),
new DictionaryInterfaceImplementerSerializer<Dictionary<string, object>, string, object>(
DictionaryRepresentation.Document,
new StringSerializer(),
new DynamicValueSerializer()));
请注意,必须为每个实际类型执行此操作,其值应该用于其中。无法对接口进行序列化程序注册。因此,如果SortedDictionary<string, object>
或SortedList<string, object>
的处理方式与Dictionary<string, object>
相同,则需要对这些类型重复注册。 (这会影响在没有_t / _v的情况下是否序列化这些类型的集合中的词典作为值,而不一定是这些类型的对象本身是否会以这种方式序列化。)
要将相同的序列化原则应用于List<object>
个对象,请使用以下注册码。
BsonSerializer.RegisterSerializer(typeof(List<object>),
new EnumerableInterfaceImplementerSerializer<List<object>, object>(
new DynamicValueSerializer()));