2012-03-20 3 views
8

Je suis nouveau sur MongoDB et j'essaie de faire en sorte que le pilote C# fonctionne en sérialisant les classes F #. Je l'ai fait travailler avec la classe automapper en utilisant mutable champs F # & un constructeur sans paramètre, mais vraiment je dois conserver l'immutabilité, donc j'ai commencé à chercher à implémenter un IBsonSerializer pour effectuer la sérialisation personnalisée. Je n'ai trouvé aucune documentation pour écrire l'un d'entre eux, alors j'ai juste essayé de déduire du code source du pilote.Implémentation du sérialiseur personnalisé MongoDB

J'ai rencontré un problème lorsque, lorsque la méthode Deserialize est appelée sur le sérialiseur, le CurrentBsonType est défini sur EndOfDocument plutôt que sur le début comme je l'espère. J'ai écrit l'équivalent en C# juste pour m'assurer que ce n'était pas quelque chose d'étrange, mais le problème persiste. La partie de sérialisation semble fonctionner correctement et peut être interrogée depuis le shell. Voici l'exemple de code:

class Calendar { 
    public string Id { get; private set; } 
    public DateTime[] Holidays { get; private set; } 

    public Calendar(string id, DateTime[] holidays) { 
     Id = id; 
     Holidays = holidays; 
    } 
} 

class CalendarSerializer : BsonBaseSerializer { 
    public override void Serialize(BsonWriter bsonWriter, Type nominalType, object value, IBsonSerializationOptions options) { 
     var calendar = (Calendar) value; 
     bsonWriter.WriteStartDocument(); 
     bsonWriter.WriteString("_id", calendar.Id); 
     bsonWriter.WriteName("holidays"); 
     var ser = new ArraySerializer<DateTime>(); 
     ser.Serialize(bsonWriter, typeof(DateTime[]), calendar.Holidays, null); 
     bsonWriter.WriteEndDocument(); 
    } 

    public override object Deserialize(BsonReader bsonReader, Type nominalType, Type actualType, IBsonSerializationOptions options) { 
     if (nominalType != typeof(Calendar) || actualType != typeof(Calendar)) 
      throw new BsonSerializationException(); 

     if (bsonReader.CurrentBsonType != BsonType.Document) 
      throw new FileFormatException(); 

     bsonReader.ReadStartDocument(); 
     var id = bsonReader.ReadString("_id"); 
     var ser = new ArraySerializer<DateTime>(); 
     var holidays = (DateTime[])ser.Deserialize(bsonReader, typeof(DateTime[]), null); 
     bsonReader.ReadEndDocument(); 
     return new Calendar(id, holidays); 
    } 

    public override bool GetDocumentId(object document, out object id, out Type idNominalType, out IIdGenerator idGenerator) { 
     var calendar = (Calendar) document; 
     id = calendar.Id; 
     idNominalType = typeof (string); 
     idGenerator = new StringObjectIdGenerator(); 
     return true; 
    } 

    public override void SetDocumentId(object document, object id) { 
     throw new NotImplementedException("SetDocumentId is not implemented"); 
    } 
} 

Ce souffle avec FileFormatException dans Deserialize lorsque le CurrentBsonType est Document non. J'utilise la dernière version 1.4 de la source du pilote.

Répondre

7

Je l'ai compris à la fin. J'aurais dû utiliser bsonReader.GetCurrentBsonType() au lieu de bsonReader.CurrentBsonType. Cela lit le BsonType dans le tampon plutôt que de simplement regarder la dernière chose là-bas. J'ai aussi corrigé un bogue suivant derserializing. La méthode mise à jour ressemble à ceci:

public override object Deserialize(BsonReader bsonReader, Type nominalType, Type actualType, IBsonSerializationOptions options) { 
    if (nominalType != typeof(Calendar) || actualType != typeof(Calendar)) 
     throw new BsonSerializationException(); 

    if (bsonReader.GetCurrentBsonType() != BsonType.Document) 
     throw new FileFormatException(); 

    bsonReader.ReadStartDocument(); 
    var id = bsonReader.ReadString("_id"); 
    bsonReader.ReadName(); 
    var ser = new ArraySerializer<DateTime>(); 
    var holidays = (DateTime[])ser.Deserialize(bsonReader, typeof(DateTime[]), null); 
    bsonReader.ReadEndDocument(); 
    return new Calendar(id, holidays); 
} 
Questions connexes