MongoDB C#中能否仅在反序列化时使用鉴别器,写入时忽略?
在MongoDB C#驱动中仅反序列化应用鉴别器、序列化忽略鉴别器的实现方案
当然可行!在MongoDB的C#驱动里,我们完全可以通过调整类映射配置或者自定义序列化逻辑,实现仅在反序列化时应用鉴别器,写回文档时忽略鉴别器字段的需求。下面我给你两种实用的实现方案:
方案一:通过BsonClassMap精准控制字段序列化行为
这种方式适合针对单个类或少数类进行精细配置,直接控制鉴别器字段_t的序列化规则:
// 注册基类的类映射 BsonClassMap.RegisterClassMap<BaseClass>(cm => { cm.AutoMap(); // 配置反序列化时使用标量鉴别器(默认的`_t`字段) cm.SetDiscriminatorConvention(new ScalarDiscriminatorConvention("_t")); // 标记基类为根类,确保反序列化时能识别子类 cm.SetIsRootClass(true); // 关键:让鉴别器字段在序列化时不被写入 var discriminatorMember = cm.GetMemberMap("_t"); if (discriminatorMember != null) { // 序列化时始终返回false,跳过该字段 discriminatorMember.SetShouldSerializeMethod(_ => false); } }); // 注册子类的类映射,指定鉴别器值(反序列化时用这个值识别子类) BsonClassMap.RegisterClassMap<DerivedClass>(cm => { cm.AutoMap(); cm.SetDiscriminator("Derived"); // 对应基类鉴别器字段的值 });
原理说明
- 反序列化阶段:驱动会读取文档中的
_t字段,根据我们注册的子类鉴别器值,将文档解析为对应的子类实例 - 序列化阶段:通过
SetShouldSerializeMethod让驱动跳过鉴别器字段的写入,最终保存到MongoDB的文档中就不会有_t字段
方案二:自定义序列化器全局调整鉴别器行为
如果需要对多个类统一应用这个规则,可以自定义序列化器,在序列化阶段临时禁用鉴别器的写入:
public class NoDiscriminatorSerializer<T> : SerializerBase<T> { private readonly IBsonSerializer<T> _baseSerializer; public NoDiscriminatorSerializer(IBsonSerializer<T> baseSerializer) { _baseSerializer = baseSerializer; } public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, T value) { // 序列化时临时替换鉴别器约定为NullDiscriminatorConvention(不写入鉴别器) var originalConvention = context.DiscriminatorConvention; context.DiscriminatorConvention = new NullDiscriminatorConvention(); _baseSerializer.Serialize(context, args, value); // 恢复原来的鉴别器约定,避免影响其他序列化操作 context.DiscriminatorConvention = originalConvention; } public override T Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) { // 反序列化时使用默认的鉴别器约定,正常识别子类 return _baseSerializer.Deserialize(context, args); } }
然后注册这个序列化器到目标类型:
// 给基类注册自定义序列化器 BsonSerializer.RegisterSerializer(typeof(BaseClass), new NoDiscriminatorSerializer<BaseClass>(BsonSerializer.LookupSerializer<BaseClass>()));
原理说明
这个序列化器相当于给目标类型套了一层“包装”:
- 反序列化时完全复用原有逻辑,正常处理鉴别器
- 序列化时临时切换鉴别器约定为
NullDiscriminatorConvention,驱动就不会写入任何鉴别器字段,完成后再恢复原约定,不影响其他类型的序列化
注意事项
- 所有需要被反序列化识别的子类,必须提前注册对应的鉴别器值(不管用哪种方案),否则驱动无法将文档映射到正确的子类
- 如果你的集合中已经存在带
_t字段的旧文档,反序列化过程不受影响;新写入的文档会自动去除_t字段 - 如果你使用强类型集合(比如
IMongoCollection<BaseClass>),确保泛型类型是基类,这样反序列化时才会触发鉴别器解析逻辑
内容的提问来源于stack exchange,提问作者priyank brahmbhatt
相关产品推荐
相关产品推荐

