簡體   English   中英

一個屬性的Mongo DB文檔反序列化為C#對象失敗

[英]Mongo DB Document deserialization to C# object for one property fails

僅當查詢對象時,我才收到屬性引用的以下錯誤

反序列化類User的Referrals屬性時發生錯誤:無法反序列化BsonType StringList<Nullable<ObjectId>>

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?>則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);
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM