2012-04-12 7 views
8

Estoy probando una serie de escenarios con MongoDb para ver cómo recuperarme de posibles problemas de datos.Campo de deserialización cuando se cambia el tipo con el controlador mongoDb csharp

Tengo clases (Direcciones con colección de Dirección) con una propiedad de código postal en Dirección que originalmente se emitió como cadena. Guardé múltiples registros de direcciones y pude recuperarlos todos bien. como este, var allAddresses = addresses.FindAllAs();

Cambié la propiedad del código postal a int y guardé algunos registros. Luego cambié la propiedad del código postal a cadena.

Cuando intento volver a leer la colección, aparece un error que se deserializa, como era de esperar. var allAddresses = addresses.FindAllAs();

Mi objetivo es poder anular la deserialización, de modo que si ocurre un error de deserialización de campo, puedo elegir ignorarlo o aplicar un valor predeterminado.

He intentado un serializador personalizado, que no funciona. Cualquier sugerencia sera apreciada.

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(); 
    } 
    } 
+0

si una respuesta resuelve su problema, usted debe aceptar la respuesta. La verificación junto a la upvote/downvote –

Respuesta

9

Hay un par de cosas sucediendo. La principal es que debe consumir la entrada independientemente del tipo o el proceso de deserialización se desincroniza. He probado su escenario escribiendo un serializador personalizado llamado ZipCodeSerializer que maneja nulos y escribe ZipCodes como cadenas, pero acepta cadenas o entradas en la entrada y convierte las entradas en cadenas.

que utilizan esta clase de prueba:

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

Y este es el serializador personalizado escribí:

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

Usted tiene que asegurarse de que el serializador personalizado está conectado, lo que puede hacer como este:

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

Así que ahora el campo Código Postal de la clase de Dirección será manejado por el custo m serializador.

creé algunos datos de prueba utilizando BsonDocument para hacer más fácil para forzar determinadas versiones almacenadas de los datos en mi colección de ensayo:

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

Esto es lo que los documentos parecían utilizando la consola mongo:

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

, así que vemos que algunos ZipCodes son cadenas y algunos son ints (también hay un nulo incluido).

Y este es mi código de prueba:

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

Y la salida de ejecutar el código de prueba es:

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

en cuenta que el código postal que era un int en la base de datos es ahora una cadena .

El código fuente completo de mi programa de prueba está disponible en:

http://www.pastie.org/3775465

+1

debo añadir que podría ser mucho más fácil de simplemente corregir los datos en la base de datos de modo que no hay tipos mixtos para ZipCode más! :) –

+0

Gracias, esta solución funciona para mí ya que no puedo actualizar un millón de registros en la base de datos;) –

Cuestiones relacionadas