Словарь -к-BsonDocument преобразования опуская поля Т

Я использую 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" } } }

есть ли способ избавиться от этих ІТ/_в вещи? Я хотел бы, чтобы полученный документ выглядел так:

  { "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 ответов


сначала вы должны сериализоваться в JSON, а затем в BSON,

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

это происходит потому, что вы указываете 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();

прямое преобразование из объекта в BSON затруднено.

вместо этого перейдите от object --> в формате 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);

переход от объектов .NET к JSON к BSON, в то же время избегая кодирования _t/_v, приведет к потере информации о типе для дат и других типов, специфичных для BSON.

решение, которое я нашел для избежания _t / _v при сохранении типов BSON, состояло в регистрации пользовательского сериализатора значений для встроенного драйвера DictionaryInterfaceImplementerSerializer (и при необходимости EnumerableInterfaceImplementerSerializer тоже). Я протестировал решение для генерации "Extended JSON", т. е. JSON со специальным синтаксисом для BSON-конкретные типы, но принцип должен быть одинаковым для прямого вывода 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>, что отражено ниже.)

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