如何重写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
相关产品推荐
相关产品推荐

