9

我正在使用 MongoDb 测试一些场景,以了解如何从可能的数据问题中恢复。

我有类(带有地址集合的地址)在地址中具有邮政编码属性,该属性最初被转换为字符串。我保存了多条地址记录,并且可以很好地检索它们。像这样, var allAddresses =addresses.FindAllAs();

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

当我尝试回读集合时,我收到反序列化错误,正如预期的那样。var allAddresses = 地址.FindAllAs();

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

我尝试了一个自定义序列化程序,但它不起作用。任何建议,将不胜感激。

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

1 回答 1

12

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

我用这个类来测试:

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

这是我编写的自定义序列化程序:

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

您必须确保自定义序列化程序已连接,您可以这样做:

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

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

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

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 时文档的样子:

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

所以我们看到一些 ZipCodes 是字符串,一些是整数(还有一个 null 被抛出)。

这是我的测试代码:

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

运行测试代码的输出是:

{ "_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 邮政编码现在是一个字符串。

我的测试程序的完整源代码位于:

http://www.pastie.org/3775465

于 2012-04-12T17:43:56.537 回答