13

我正在使用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

4 回答 4

17

您应先序列化为 JSON,然后再序列化为 BSON,

var jsonDoc = Newtonsoft.Json.JsonConvert.SerializeObject(dictionary);
var bsonDoc = MongoDB.Bson.Serialization.BsonSerializer.Deserialize<BsonDocument>(jsonDoc);
于 2015-06-28T05:02:41.483 回答
6

发生这种情况是因为您object为字典值指定了类型,但实际上Dictionary<string, object>对特定记录值使用了类型。因此,CSharp 驱动程序会保存具体类型的全名,以便将来正确反序列化此文档。您还可以在此处阅读有关它的更多信息:使用 CSharp 驱动程序序列化文档:多态类和鉴别器

要获得所需的结果,您应该为字典值指定具体类型:

var dictionary = new Dictionary<string, Dictionary<string, object>>
{
    { "person", new Dictionary<string, object> { { "name", "John" } } }
};
var document = dictionary.ToBsonDocument();
于 2013-11-05T20:28:07.190 回答
3

从 .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)方法也需要编辑。(就我而言,我还想避免 _t/_v 编码IEnumerable<object>,如下所示。)

    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()));
于 2018-01-19T17:13:12.707 回答
2

从对象到 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<BsonDocument>(json);
于 2016-01-20T20:17:26.227 回答