You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MongoDB反序列化:混合类型字段转对象数组报错排查

问题

有一个混合类型的字段(可为单个Association对象或Association对象数组),尝试通过自定义序列化器将其反序列化为Association[],代码如下:

class AssociationSerializer : SerializerBase<Association[]>
{
    public override Association[] Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
    {
        var type = context.Reader.GetCurrentBsonType();

        switch (type)
        {
            case BsonType.Array:
                var arraySerializer = new ArraySerializer<Association>();
                return arraySerializer.Deserialize(context, new BsonDeserializationArgs());

            case BsonType.Document:
                var bsonDocument = context.Reader.ToBsonDocument();
                var association= BsonSerializer.Deserialize<Association>(bsonDocument);
                return new[] { association };

            default:
                throw new NotSupportedException();
        }
    }
}

运行时抛出错误:

System.InvalidOperationException: ReadBsonType can only be called when State is Type, not when State is Value.
at MongoDB.Bson.IO.BsonReader.ThrowInvalidState(String methodName, BsonReaderState[] validStates)
at MongoDB.Bson.IO.BsonBinaryReader.ReadBsonType()
at MongoDB.Bson.Serialization.BsonClassMapSerializer1.DeserializeClass(BsonDeserializationContext context) at MongoDB.Bson.Serialization.BsonClassMapSerializer1.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
at MongoDB.Bson.Serialization.IBsonSerializerExtensions.Deserialize[TValue](IBsonSerializer`1 serializer, BsonDeserializationContext context)

相关实体类:

public class Association
{
    public string Id { get; set; }
    public int Type { get; set; }
}

JSON示例:

{   
    "association" : [
        {
            "_id" : "b8e0a770-951b-5e85-84a6-8ca8cd0998e0",
            "type" : 0
        }
    ]
}   
    
{
    "association" : {
        "_id" : "08dc1cb0-0f88-4dcf-70db-ff3b8c000003"
    }
}
解决方案

错误原因

问题出在处理BsonType.Document的分支:调用context.Reader.ToBsonDocument()会将Bson阅读器的指针移动到整个文档末尾,后续父序列化器尝试继续读取时,阅读器状态处于Value而非预期的Type,触发状态异常。

修正后的序列化器代码

class AssociationSerializer : SerializerBase<Association[]>
{
    public override Association[] Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
    {
        var reader = context.Reader;
        var currentType = reader.GetCurrentBsonType();

        switch (currentType)
        {
            case BsonType.Array:
                var arraySerializer = new ArraySerializer<Association>();
                return arraySerializer.Deserialize(context, args);

            case BsonType.Document:
                // 直接从当前阅读器位置反序列化单个对象,避免指针移动到无效位置
                var singleAssociation = BsonSerializer.Deserialize<Association>(reader);
                return new[] { singleAssociation };

            default:
                throw new NotSupportedException($"不支持的Bson类型:{currentType}");
        }
    }
}

额外注意事项

需确保序列化器正确关联到目标字段:

  • 方式一:在实体类字段上标记特性:
    public class ParentEntity
    {
        [BsonSerializer(typeof(AssociationSerializer))]
        public Association[] Association { get; set; }
    }
    
  • 方式二:通过BsonClassMap注册:
    BsonClassMap.RegisterClassMap<ParentEntity>(cm =>
    {
        cm.AutoMap();
        cm.GetMemberMap(x => x.Association)
          .SetSerializer(new AssociationSerializer());
    });
    

内容的提问来源于stack exchange,提问作者Sameer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 03:57:44