MongoDb.Driver 2.4 изменение типа данных десерилизации

У меня есть следующий класс POCO:

class MyClass {
    public Objectid _id {get;set;}
    public string property1 {get;set;}
    public string property2 {get;set;}
    public int property3 {get;set;}
}

Объект хранится в коллекции MongoDb. Данные имеют правильные типы данных в результирующем bson:

property1: "SomeString"
property2: "12345"
property3: 98765

Когда я пытаюсь запросить коллекцию:

var items = db.GetCollection<MyClass>("MyClass").AsQueryable().Select(x => x.property1 == "SomeString").ToList();

Я получаю сообщение об ошибке, указывающее, что не может быть десериализована property2: Невозможно десериализовать 'String' из BsonType 'Int64'

Я пытаюсь десериализовать строковое значение из документа bson в БД в строковое значение на моем объекте.

Почему BsonSerializer пытается преобразовать его в десятичную? В этом случае значение оказывается числовым, но поле определяется в классе как строка, поскольку значение обычно буквенно-цифровое.

Я использую пакет MongoDb.Driver v2.4, в VS2013.

1 ответ

Для изменения типа свойства Mongo вам необходимо написать собственный Serializer для этого свойства.

Это оригинальный объект, и вы сохранили несколько таких объектов в Mongo.

public class TestingObject
{
    public string FirstName { get; set; }

    public string LastName { get; set; }

    public int TestingObjectType { get; set; }
}

Теперь нам нужно изменить TestObjectType с int на строку

Это наш новый класс

public class TestingObject
{
    public string FirstName { get; set; }

    public string LastName { get; set; }

    public string TestingObjectType { get; set; }
}

Затем вы получите

Невозможно десериализовать 'String' из BsonType 'Int64'

Вам нужен сериализатор для обработки конвертации.

public class TestingObjectTypeSerializer : IBsonSerializer
{
    public Type ValueType { get; } = typeof(string);

    public object Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
    {
        if (context.Reader.CurrentBsonType == BsonType.Int32) return GetNumberValue(context);

        return context.Reader.ReadString();
    }

    public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value)
    {
        context.Writer.WriteString(value as string);
    }

    private static object GetNumberValue(BsonDeserializationContext context)
    {
        var value = context.Reader.ReadInt32();

        switch (value)
        {
            case 1:
                return "one";
            case 2:
                return "two";
            case 3:
                return "three";
            default:
                return "BadType";
        }
    }
}

Ключевой частью является метод десериализации. Только если тип int32, вы хотите запустить логику преобразования. Если тип является чем-то еще, мы будем предполагать, что это уже строка и возвращаем это значение.

Сериализация только из WriteString и любой документ, обновленный или сохраненный, будет иметь новое значение в виде строки.

Теперь вам просто нужно обновить объект, чтобы указать свойству использовать ваш сериализатор

public class TestingObject
{
    public string FirstName { get; set; }

    public string LastName { get; set; }

    [BsonSerializer(typeof(TestingObjectTypeSerializer))]
    public string TestingObjectType { get; set; }
}

В следующий раз, когда вы прочитаете его из Монго, вы не должны получить ошибку.

Другие вопросы по тегам