字典<string,object =“”> - to-BsonDocument转换省略_t字段</string,>

时间:2013-11-05 10:10:14

标签: c# mongodb dictionary bson

我正在使用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时,似乎此序列化程序没有太多选项。

4 个答案:

答案 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()));