仅在查询对象时收到以下属性引用错误
反序列化类的引用属性时出错 用户:无法从 BsonType 反序列化
List<Nullable<ObjectId>>
String
.
C# 类
[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 循环迭代,就会发生此异常
foreach (var item in myusers){}
并非所有文档都会发生这种情况,只有某些文档才会发生这种情况。有什么方法可以忽略导致该错误的文档吗?
幸运的是,错误消息足够清晰,可以了解问题的根本原因。集合中有一些文档users
这些文档是使用不同的架构保存的,其中referrals
只是一个字符串,而不是一个ObjectId
数组。现在,当您尝试反序列化这些对象时,您会得到公平的错误,即无法将String
反序列化为List<ObjectId?>
。
如果当前数据库仅包含一些测试数据,则可以清除集合并从头开始。只要不再保存具有旧架构的文档,您将不会再次遇到该错误。
如果必须保留现有数据,则应手动删除具有旧架构的文档或将其数据迁移到新架构,以便可以成功反序列化这些文档。
但是,如果无法删除具有过时架构的数据,则应实现自定义序列化程序,以便从数据库读取数据可以成功。下面是在反序列化过程中忽略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;
}
}
您可以通过BsonSerializer
属性为referrals
字段设置此序列化程序:
[BsonIgnoreExtraElements]
public class User : Document
{
[BsonDefaultValue(null)]
[BsonSerializer(typeof(FixingReferralsSerializer))]
public List<ObjectId?> referrals { get; set; }
}
如果可以将referrals
字段的类型从List<ObjectId?>
更改为Array<ObjectId?>
,序列化程序类会简单得多。在这种情况下,您可以将序列化程序实现基于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);
}
}