2012-04-12 57 views
8

我正在使用MongoDb测试多个方案以查看如何从可能的数据问题中恢复。使用MongoDb csharp驱动程序更改类型时的反序列化字段

我有地址中的zipcode属性的类(地址集合的地址),最初被转换为字符串。我保存了多个地址记录,并可以很好地检索它们。 这样, var allAddresses = addresses.FindAllAs();

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

当我试图读回集合时,我得到一个错误反序列化,如预期的那样。 var allAddresses = addresses.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(); 
    } 
    } 
+0

如果答案解决您的问题,您应该接受的答案。在upvote/downvote – 2016-03-17 18:00:52

回答

9

有几件事情正在进行。主要的一点是,不管类型如何,您都必须使用输入,否则反序列化过程将不同步。我已经测试过编写一个名为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字段将由custo处理m序列化程序。

我创建使用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)); 

下面介绍一下文件看起来像使用蒙戈外壳:

> 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

+1

旁边的检查我应该补充说,修复数据库中的数据可能会简单很多,因此ZipCode不再有混合类型! :) – 2012-04-12 17:46:04

+0

谢谢,这个解决方案适用于我,因为我无法更新数据库中的数百万条记录;) – 2014-02-10 04:13:23

相关问题