Вопрос по mongodb – Поле десериализации при изменении типа с помощью драйвера MongoDb csharp

8

Я тестирую ряд сценариев с MongoDb, чтобы увидеть, как устранить возможные проблемы с данными.

У меня есть классы (адреса с коллекцией адресов) со свойством почтового индекса в адрес, который изначально был приведен в виде строки. Я сохранил несколько записей адресов и мог получить их все в порядке. как это, var allAddresses = address.FindAllAs ();

Я изменил свойство почтового индекса на int и сохранил некоторые записи. Затем я изменил свойство почтового индекса обратно на строку.

Когда я пытаюсь прочитать коллекцию обратно, я получаю ошибку десериализации, как и ожидалось. var allAddresses = address.FindAllAs ();

Моя цель - иметь возможность переопределить десериализацию, поэтому, если возникает ошибка десериализации поля, я могу либо проигнорировать ее, либо применить значение по умолчанию.

Я пробовал собственный сериализатор, который не работает. Мы ценим любые предложения.

<code>public class MyCustomSerializer : BsonBaseSerializer
  {

    public override object Deserialize(BsonReader bsonReader, Type nominalType,  IBsonSerializationOptions options)
    {
      if (bsonReader.CurrentBsonType != BsonType.String)
      {
        return string.Empty;
      }

      return bsonReader.ReadString();
    }

    public override void Serialize(
               BsonWriter bsonWriter,
               Type nominalType,
               object value,
               IBsonSerializationOptions options)
    {
      bsonWriter.WriteStartDocument();
      bsonWriter.WriteName("ZipCode");
      bsonWriter.WriteString(value.ToString());
      bsonWriter.WriteEndDocument();
    }
  }
</code>
если ответ решит вашу проблему, вы должны принять ответ. Чек рядом с upvote / downvote Dave Alperovich

Ваш Ответ

1   ответ
9

Есть несколько вещей, происходящих. Основным является то, что вы должны использовать ввод независимо от типа, иначе процесс десериализации не синхронизируется. Я протестировал ваш сценарий, написав собственный сериализатор ZipCodeSerializer, который обрабатывает значения NULL и записывает ZipCodes в виде строк, но принимает на входе либо строку, либо целые числа и преобразует целые числа в строку.

Я использовал этот класс для проверки:

public class Address
{
    public ObjectId Id;
    public string ZipCode;
}

И это пользовательский сериализатор, который я написал:

public class ZipCodeSerializer : BsonBaseSerializer
{
    public override object Deserialize(BsonReader bsonReader, Type nominalType, Type actualType, IBsonSerializationOptions options)
    {
        var bsonType = bsonReader.CurrentBsonType;
        switch (bsonType)
        {
            case BsonType.Null:
                bsonReader.ReadNull();
                return null;
            case BsonType.String:
                return bsonReader.ReadString();
            case BsonType.Int32:
                return bsonReader.ReadInt32().ToString();
            default:
                var message = string.Format("ZipCodeSerializer expects to find a String or an Int32, not a {0}.", bsonType);
                throw new BsonSerializationException(message);
        }
    }

    public override void Serialize(BsonWriter bsonWriter, Type nominalType, object value, IBsonSerializationOptions options)
    {
        if (value == null)
        {
            bsonWriter.WriteNull();
        }
        else
        {
            bsonWriter.WriteString((string)value);
        }
    }
}

Вы должны убедиться, что пользовательский сериализатор подключен, что вы можете сделать так:

BsonClassMap.RegisterClassMap<Address>(cm =>
    {
        cm.AutoMap();
        cm.GetMemberMap(a => a.ZipCode).SetSerializer(new ZipCodeSerializer());
    });

Так что теперь поле ZipCode класса Address будет обрабатываться пользовательским сериализатором.

Я создал некоторые тестовые данные с помощью BsonDocument, чтобы упростить принудительное использование определенных сохраненных версий данных в моей тестовой коллекции:

collection.Drop();
collection.Insert(new BsonDocument());
collection.Insert(new BsonDocument("ZipCode", BsonNull.Value));
collection.Insert(new BsonDocument("ZipCode", "12345"));
collection.Insert(new BsonDocument("ZipCode", 56789));

Вот как выглядели документы, используя оболочку Монго:

> db.test.find()
{ "_id" : ObjectId("4f871374e447ad238040e346") }
{ "_id" : ObjectId("4f871374e447ad238040e347"), "ZipCode" : null }
{ "_id" : ObjectId("4f871374e447ad238040e348"), "ZipCode" : "12345" }
{ "_id" : ObjectId("4f871374e447ad238040e349"), "ZipCode" : 56789 }
>

Итак, мы видим, что некоторые ZipCode являются строками, а некоторые являются целочисленными (здесь также добавляется ноль).

И это мой тестовый код:

foreach (var document in collection.FindAll())
{
    Console.WriteLine(document.ToJson());
}

И результат выполнения тестового кода:

{ "_id" : ObjectId("4f871374e447ad238040e346"), "ZipCode" : null }
{ "_id" : ObjectId("4f871374e447ad238040e347"), "ZipCode" : null }
{ "_id" : ObjectId("4f871374e447ad238040e348"), "ZipCode" : "12345" }
{ "_id" : ObjectId("4f871374e447ad238040e349"), "ZipCode" : "56789" }
Press Enter to continue

Обратите внимание, что почтовый индекс, который был int в базе данных, теперь является строкой.

Полный исходный код моей тестовой программы доступен по адресу:

http://www.pastie.org/3775465

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded

Похожие вопросы