在C#中使用MongoDB.Bson实现MongoDB多态查询的问题
解决MongoDB多态文档反序列化问题
问题核心在于MongoDB驱动无法自动识别文档对应的具体子类,导致反序列化时要么丢失子类属性,要么因存在未知字段报错。以下是具体解决步骤:
1. 配置类型鉴别器(关键)
MongoDB驱动需要通过类型鉴别器字段(默认是_t)区分不同子类,需在基类上添加[BsonDiscriminator(RootClass = true)]特性,配合已有的[BsonKnownTypes]让驱动自动生成并识别鉴别器:
[BsonDiscriminator(RootClass = true)] [BsonKnownTypes(typeof(Cat), typeof(Dog))] public class Animal { public int Code; } [BsonDiscriminator(RootClass = true)] [BsonKnownTypes(typeof(Lion), typeof(Tiger))] public class Cat : Animal { public string CatProperty; } public class Dog : Animal { } public class Lion : Cat { } public class Tiger : Cat { }
配置后,MongoDB存储文档时会自动添加_t字段标记类型(例如Cat类型文档会带"_t": "Cat",Lion类型会带"_t": "Lion"),查询时驱动会根据该字段将文档反序列化为对应的具体子类。
2. 可选:全局配置忽略未知字段(避免序列化报错)
如果已有文档未包含鉴别器字段,或需临时兼容额外字段,可全局配置驱动忽略未知字段,防止因文档存在子类属性但反序列化到基类时抛出异常:
// 在应用启动时配置(如Program.cs) MongoDB.Bson.Serialization.BsonSerializer.Configure(config => { config.IgnoreExtraElements = true; });
也可以给单个类添加[BsonIgnoreExtraElements]特性,仅对该类生效。
3. 保持原有查询逻辑即可
完成上述配置后,原查询代码就能正确返回完整的具体类型对象,可通过类型判断访问子类属性:
var collection = _database.GetCollection<Animal>("collectionName"); var myAnimal = collection.Find(animal => animal.Code == 5).FirstOrDefault(); // 示例:判断具体类型并访问子类属性 if (myAnimal is Cat cat) { Console.WriteLine(cat.CatProperty); } else if (myAnimal is Lion lion) { // 访问Lion的专属属性 }
备选:手动注册类映射
若不想用特性配置,也可在应用启动时手动注册类映射,效果与特性一致:
MongoDB.Bson.Serialization.BsonClassMap.RegisterClassMap<Animal>(cm => { cm.AutoMap(); cm.SetIsRootClass(true); cm.AddKnownType(typeof(Cat)); cm.AddKnownType(typeof(Dog)); }); MongoDB.Bson.Serialization.BsonClassMap.RegisterClassMap<Cat>(cm => { cm.AutoMap(); cm.SetIsRootClass(true); cm.AddKnownType(typeof(Lion)); cm.AddKnownType(typeof(Tiger)); }); MongoDB.Bson.Serialization.BsonClassMap.RegisterClassMap<Dog>(); MongoDB.Bson.Serialization.BsonClassMap.RegisterClassMap<Lion>(); MongoDB.Bson.Serialization.BsonClassMap.RegisterClassMap<Tiger>();
内容的提问来源于stack exchange,提问作者chani
相关产品推荐
相关产品推荐

