使用MongoDb csharp驱动程序更改类型时反序列化字段 [英] Deserializing field when type is changed using MongoDb csharp driver

查看:87
本文介绍了使用MongoDb csharp驱动程序更改类型时反序列化字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在用MongoDb测试多种方案,以了解如何从可能的数据问题中恢复.

I am testing a number of scenarios with MongoDb to see how to recover from possible data issues.

我有一些类(带有地址集合的地址),该类的地址最初是转换为字符串的地址中的邮政编码属性.我保存了多个地址记录,可以将它们全部恢复. 像这样, var allAddresses = addresss.FindAllAs();

I have classes (Addresses with collection of Address) with a zipcode property in Address which was originally cast as string. I saved out multiple records of Addresses and could retrieve them all fine. like this, var allAddresses = addresses.FindAllAs();

我将邮政编码属性更改为int并保存了一些记录. 然后,我将邮政编码属性更改回字符串.

I changed the zip code property to int and saved some records. I then changed the zip code property back to string.

当我尝试读回集合时,按预期方式出现反序列化错误. var allAddresses = addresss.FindAllAs();

When I attempt to read the collection back I get an error deserializing, as expected. var allAddresses = addresses.FindAllAs();

我的目标是能够覆盖反序列化,因此,如果发生字段反序列化错误,我可以选择忽略它或应用默认值.

My goal is to be able to override the deserialization so if an field deserialization error occurs I can choose to either ignore it or apply a default value.

我尝试了一个自定义序列化器,该序列化器不起作用.任何建议,将不胜感激.

I have tried a custom serializer, which is not working. Any suggestions would be appreciated.

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

推荐答案

发生了几件事情.主要的问题是无论类型如何,反序列化过程都不同步,您都必须使用输入.我已经测试了您的方案,编写了一个名为ZipCodeSerializer的自定义序列化程序,该序列化程序可以处理空值并将ZipCodes写入字符串,但是在输入时接受字符串或整数,并将整数转换为字符串.

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.

我使用此类进行测试:

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

现在,Address类的ZipCode字段将由自定义序列化程序处理.

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

我使用BsonDocument创建了一些测试数据,以使其易于在测试集中强制存储特定版本的数据:

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

这是使用mongo shell的文档的样子:

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

所以我们看到有些ZipCode是字符串,有些是ints(也有一个null抛出).

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

这是我的测试代码:

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

请注意,数据库中int邮政编码现在是一个字符串.

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

这篇关于使用MongoDb csharp驱动程序更改类型时反序列化字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆