只有在查询对象
时才会出现属性引用的错误反序列化类的referrals属性时发生错误 用户:无法从BsonType反序列化
List<Nullable<ObjectId>>
String
。
C#class
[BsonIgnoreExtraElements]
public class User : MongoEntity
{
[BsonDefaultValue(null)]
public List<ObjectId?> referrals { get; set; }
}
查询文件
var users = MongoConnectionHandler.GetDB().GetCollection<User>("users");
var myusers = users.AsQueryable<User>();
当foreach循环的soons迭代时会发生此异常
foreach (var item in myusers){}
仅针对某些文档并非针对所有文档发生。有什么办法可以忽略造成错误的文件吗?
答案 0 :(得分:2)
幸运的是,错误消息足够清楚,可以理解问题的根本原因。您在users
集合中有一些使用不同架构保存的文档,其中referrals
只是一个字符串,而不是ObjectId
的数组。现在,当您尝试反序列化这些对象时,会出现公平错误,String
无法反序列化为List<ObjectId?>
。
如果您的数据库当前只包含一些测试数据,则可以清除该集合并从头开始。至于具有旧架构的文档将不再保存,您将不会再次遇到错误。
如果必须保留现有数据,则应手动删除旧架构的文档或将其数据迁移到新架构,以便可以成功地反序列化这些文档。
但是,如果您无法删除具有过期模式的数据,则应实现自定义序列化程序,以便从DB中读取数据可以成功。以下是反序列化期间忽略String
值的示例序列化程序:
public class FixingReferralsSerializer : EnumerableSerializerBase<List<ObjectId?>>
{
public override List<ObjectId?> Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
if (context.Reader.CurrentBsonType == BsonType.String)
{
context.Reader.ReadString();
return null;
}
return base.Deserialize(context, args);
}
protected override void AddItem(object accumulator, object item)
{
((List<ObjectId?>)accumulator).Add((ObjectId?)item);
}
protected override object CreateAccumulator()
{
return new List<ObjectId?>();
}
protected override IEnumerable EnumerateItemsInSerializationOrder(List<ObjectId?> value)
{
return value;
}
protected override List<ObjectId?> FinalizeResult(object accumulator)
{
return (List<ObjectId?>)accumulator;
}
}
您可以通过referrals
属性为BsonSerializer
字段设置此序列化程序:
[BsonIgnoreExtraElements]
public class User : Document
{
[BsonDefaultValue(null)]
[BsonSerializer(typeof(FixingReferralsSerializer))]
public List<ObjectId?> referrals { get; set; }
}
如果您可以将referrals
字段的类型从List<ObjectId?>
更改为Array<ObjectId?>
,那么 Serializer类会更简单。在这种情况下,您可以在ArraySerializer<T>
上实现序列化程序实现:
public class FixingReferralsSerializer : ArraySerializer<ObjectId?>
{
public override ObjectId?[] Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
if (context.Reader.CurrentBsonType == BsonType.String)
{
context.Reader.ReadString();
return null;
}
return base.Deserialize(context, args);
}
}