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

时间:2018-01-21 05:20:27

标签: c# mongodb

只有在查询对象

时才会出现属性引用的错误
  

反序列化类的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){}

仅针对某些文档并非针对所有文档发生。有什么办法可以忽略造成错误的文件吗?

1 个答案:

答案 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);
    }
}