2012-04-12 8 views
8

Sto testando un numero di scenari con MongoDb per vedere come recuperare da eventuali problemi relativi ai dati.Deserializzazione campo quando il tipo viene modificato utilizzando il driver csharp MongoDb

Ho classi (Indirizzi con raccolta di indirizzo) con una proprietà di codice di avviamento postale in Indirizzo che originariamente era stata convertita in stringa. Ho salvato più record di indirizzi e li ho recuperati tutti bene. in questo modo, var allAddresses = addresses.FindAllAs();

Ho modificato la proprietà del codice di avviamento postale su int e salvato alcuni record. Quindi ho cambiato la proprietà del codice di avviamento postale in stringa.

Quando tento di leggere la raccolta, si verifica un errore di deserializzazione, come previsto. var allAddresses = addresses.FindAllAs();

Il mio obiettivo è di essere in grado di ignorare la deserializzazione, quindi se si verifica un errore di deserializzazione del campo, posso scegliere di ignorarlo o applicare un valore predefinito.

Ho provato un serializzatore personalizzato, che non funziona. Tutti i suggerimenti sarebbero apprezzati.

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

se una risposta risolve il problema, è necessario accettare la risposta. Il controllo accanto a upvote/downvote –

risposta

9

Ci sono un paio di cose in corso. Il principale è che è necessario consumare l'input indipendentemente dal tipo o il processo di deserializzazione non è sincronizzato. Ho testato il tuo scenario scrivendo un serializzatore personalizzato chiamato ZipCodeSerializer che gestisce i valori null e scrive ZipCode come stringhe, ma accetta stringhe o int in input e converte i valori in stringa.

Ho usato questa classe per prova:

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

e questo è il serializzatore personalizzato che ho scritto:

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

È necessario assicurarsi che il serializzatore personalizzato è collegato, che si può fare così:

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

Così ora il campo ZipCode della classe Indirizzo sarà gestito dal cliente m serializzatore.

ho creato alcuni dati di prova utilizzando BsonDocument per rendere più facile per forzare particolari versioni memorizzate dei dati nella mia collezione di prova:

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

Ecco quello che i documenti sembravano utilizzando la shell mongo:

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

quindi vediamo che alcuni ZipCode sono stringhe e alcuni sono ints (c'è anche un null gettato in).

E questo è il mio codice di prova:

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

E l'uscita di eseguire il codice di prova è:

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

Si noti che il codice postale che era un int nel database è ora una stringa .

Il codice sorgente completo del mio programma di test è disponibile all'indirizzo:

http://www.pastie.org/3775465

+1

Devo aggiungere che potrebbe essere molto più semplice correggere i dati nel database in modo che non ci siano più tipi misti per ZipCode! :) –

+0

Grazie, questa soluzione funziona per me poiché non riesco ad aggiornare milioni di record nel database;) –

Problemi correlati