Deserializing field when type is changed using MongoDb csharp driver

≡放荡痞女 提交于 2019-12-03 12:24:12

There are a couple of things going on. The main one is that you have to consume the input regardless of type or the deserialization process gets out of sync. I've tested your scenario writing a custom serializer called ZipCodeSerializer which handles nulls and writes ZipCodes as strings, but accepts either string or ints on input and converts the ints to string.

I used this class to test:

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

And this is the custom serializer I wrote:

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

You have to make sure the custom serializer is hooked up, which you can do like this:

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

So now the ZipCode field of the Address class will be handled by the custom serializer.

I created some test data using BsonDocument to make it easy to force particular stored versions of the data in my test collection:

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

Here's what the documents looked like using the mongo shell:

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

so we see that some ZipCodes are strings and some are ints (there's also a null thrown in).

And this is my test code:

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

And the output of running the test code is:

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

Notice that the zipcode that was an int in the database is now a string.

The full source code of my test program is available at:

http://www.pastie.org/3775465

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!