Mongo DB 文档反序列化为一个属性的 C# 对象失败



仅在查询对象时收到以下属性引用错误

反序列化类的引用属性时出错 用户:无法从 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);
}
}

最新更新