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

如何重写BsonSerializer的Serialize方法解决MongoDB多Schema序列化问题?

解决MongoDB中两种Phones格式的序列化与反序列化问题

问题背景

MongoDB中存在两种phones字段的存储格式:

  • 嵌套文档形式:
{
    ...
    phones: 
    {
        0: {number:"123"},
        1: {number:"456"}
    }
    ...
}
  • 数组形式:
{
    ...
    phones: 
        [
            {number:"123"},
            {number:"456"}
        ]
    ...
}

已通过自定义BsonSerializer解决反序列化问题,但插入数据时触发序列化错误:

An error occurred while serializing the phones property of class App.Models.Order: Type App.Models.Phone is not configured as a type that is allowed to be serialized for this instance of ObjectSerializer.


方案一:完善自定义序列化器的Serialize方法

1. 序列化为数组格式(推荐,MongoDB标准列表存储方式)

修改自定义序列化器的Serialize方法,显式将List<Phone>序列化为BSON数组:

public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, List<Phone> value)
{
    var writer = context.Writer;
    writer.WriteStartArray();
    foreach (var phone in value)
    {
        BsonSerializer.Serialize(writer, phone);
    }
    writer.WriteEndArray();
}

2. 序列化为嵌套文档格式(兼容旧数据格式)

如果需要和旧数据保持一致的嵌套文档格式,修改为:

public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, List<Phone> value)
{
    var writer = context.Writer;
    writer.WriteStartDocument();
    for (int i = 0; i < value.Count; i++)
    {
        writer.WriteName(i.ToString());
        BsonSerializer.Serialize(writer, value[i]);
    }
    writer.WriteEndDocument();
}

补充:确保Phone类的序列化配置

为Phone类添加序列化标记,避免字段不匹配问题:

[BsonIgnoreExtraElements]
public class Phone
{
    public string number { get; set; }
}

方案二:全局BsonTypeMap配置(更简洁)

无需编写自定义序列化器,通过全局类型映射兼容两种格式:

// 在应用启动阶段(如Program.cs)执行配置
BsonTypeMap.RegisterTypeMap(
    typeof(List<Phone>),
    new BsonTypeMap
    {
        // 允许将BSON文档和数组都反序列化为List<Phone>
        AllowDeserializationFromBsonTypes = new[] { BsonType.Array, BsonType.Document }
    }
);

// 注册List<Phone>的序列化器,确保序列化为数组(默认行为)
BsonSerializer.RegisterSerializer(typeof(List<Phone>), new EnumerableSerializerBase<List<Phone>, Phone>(new PhoneSerializer()));

这种方式全局生效,既解决反序列化兼容问题,又统一序列化输出格式,代码更简洁。


错误原因

原序列化错误是因为自定义序列化器的基类未正确获取Phone类型的序列化器,导致ObjectSerializer无法识别该类型。显式调用BsonSerializer.Serialize(writer, phone)可直接使用Phone的对应序列化器,规避此问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 17:55:59