MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

Desserializando o campo quando o tipo é alterado usando o driver MongoDb csharp


Há algumas coisas acontecendo. A principal é que você precisa consumir a entrada independentemente do tipo ou o processo de desserialização fica fora de sincronia. Eu testei seu cenário escrevendo um serializador personalizado chamado ZipCodeSerializer que lida com nulos e grava ZipCodes como strings, mas aceita string ou ints na entrada e converte os ints em string.

Usei esta classe para testar:
public class Address
{
    public ObjectId Id;
    public string ZipCode;
}

E este é o serializador personalizado que escrevi:
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);
        }
    }
}

Você precisa garantir que o serializador personalizado esteja conectado, o que você pode fazer assim:
BsonClassMap.RegisterClassMap<Address>(cm =>
    {
        cm.AutoMap();
        cm.GetMemberMap(a => a.ZipCode).SetSerializer(new ZipCodeSerializer());
    });

Portanto, agora o campo ZipCode da classe Address será tratado pelo serializador personalizado.

Eu criei alguns dados de teste usando BsonDocument para facilitar a força de determinadas versões armazenadas dos dados em minha coleção de teste:
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));

Aqui está a aparência dos documentos usando o shell mongo:
> db.test.find()
{ "_id" : ObjectId("4f871374e447ad238040e346") }
{ "_id" : ObjectId("4f871374e447ad238040e347"), "ZipCode" : null }
{ "_id" : ObjectId("4f871374e447ad238040e348"), "ZipCode" : "12345" }
{ "_id" : ObjectId("4f871374e447ad238040e349"), "ZipCode" : 56789 }
>

então vemos que alguns ZipCodes são strings e alguns são ints (também há um null lançado).

E este é o meu código de teste:
foreach (var document in collection.FindAll())
{
    Console.WriteLine(document.ToJson());
}

E a saída da execução do código de teste é:
{ "_id" : ObjectId("4f871374e447ad238040e346"), "ZipCode" : null }
{ "_id" : ObjectId("4f871374e447ad238040e347"), "ZipCode" : null }
{ "_id" : ObjectId("4f871374e447ad238040e348"), "ZipCode" : "12345" }
{ "_id" : ObjectId("4f871374e447ad238040e349"), "ZipCode" : "56789" }
Press Enter to continue

Observe que o CEP que era um int no banco de dados agora é uma string.

O código fonte completo do meu programa de teste está disponível em:

http://www.pastie.org/3775465