我正在使用MongoDb测试一些场景,以了解如何从可能的数据问题中恢复。
我有一个类(地址集合的地址),其地址中的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 :(得分:10)
有几件事正在发生。主要的一点是,无论类型如何,或者反序列化过程都不同步,您必须使用输入。我已经测试了你的场景,编写了一个名为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是字符串,一些是int(也有一个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的zipcode现在是一个字符串。
我的测试程序的完整源代码可在以下网址获得: