MongoDb自定义集合序列化器

我有四个简单的课程

public class Zoo{ public ObjectId Id { get; set; } public List Animals { get; set; } } public class Animal{ public ObjectId Id { get; set; } public string Name { get; set; } } public class Tiger : Animal{ public double Height { get; set; } } public class Zebra : Animal{ public long StripesAmount { get; set; } } 

我创建了自定义序列化器,它允许我将Animal对象存储在一个不同的集合中(“animals”)。

 class MyAnimalSerializer : SerializerBase { public override void Serialize(MongoDB.Bson.Serialization.BsonSerializationContext context, MongoDB.Bson.Serialization.BsonSerializationArgs args, Animal value) { context.Writer.WriteStartDocument(); context.Writer.WriteName("_id"); context.Writer.WriteObjectId(ObjectId.GenerateNewId()); context.Writer.WriteName("_t"); context.Writer.WriteString(value.GetType().Name); context.Writer.WriteName("Name"); context.Writer.WriteString(value.Name); switch (value.AnimalType) { case AnimalType.Tiger: context.Writer.WriteName("Height"); context.Writer.WriteDouble((value as Tiger).Height); break; case AnimalType.Zebra: context.Writer.WriteName("StripesAmount"); context.Writer.WriteInt32((value as Zebra).StripesAmount); break; default: break; } context.Writer.WriteEndDocument(); } public override Animal Deserialize(MongoDB.Bson.Serialization.BsonDeserializationContext context, MongoDB.Bson.Serialization.BsonDeserializationArgs args) { context.Reader.ReadStartDocument(); ObjectId id = context.Reader.ReadObjectId(); string object_type = context.Reader.ReadString(); string animal_name = context.Reader.ReadString(); switch (object_type) { case "Tiger": double tiger_height = context.Reader.ReadDouble(); context.Reader.ReadEndDocument(); return new Tiger() { Id = id, Name = animal_name, Height = tiger_height }; default: long zebra_stripes = context.Reader.ReadInt64(); context.Reader.ReadEndDocument(); return new Zebra() { Id = id, Name = animal_name, StripesAmount = zebra_stripes }; } return null; } } 

哪个效果很好,也允许我这样的事情:

 MongoDB.Bson.Serialization.BsonSerializer.RegisterSerializer(typeof(Animal), new MyAnimalSerializer()); IMongoCollection collection = db.GetCollection("animals"); var lst = await collection.Find(new BsonDocument()).ToListAsync(); 

但是,当动物存储在Zoo中并且无法从Zoo集合中反序列化Zoo时,我不能这样做

 IMongoCollection collection = db.GetCollection("zoocollection"); var lst = await collection.Find(new BsonDocument()).ToListAsync(); //not working here 

是否可以为该字段创建自定义集合序列化程序?

 public List Animals { get; set; } 

谁能举个例子? 提前致谢。

您是否访问过此文档页面? 还有多态类的例子。

这是我存储对象的例子:

 public class Zoo { [BsonId] public ObjectId Id { get; set; } public List Animals { get; set; } } [BsonDiscriminator(RootClass = true)] [BsonKnownTypes(typeof(Tiger), typeof(Zebra))] public class Animal { [BsonId] public ObjectId Id { get; set; } public string Name { get; set; } } public class Tiger : Animal { public double Height { get; set; } } public class Zebra : Animal { public long StripesAmount { get; set; } } public class MongoDocumentsDatabase { ///  /// MongoDB Server ///  private readonly MongoClient _client; ///  /// Name of database ///  private readonly string _databaseName; public MongoUrl MongoUrl { get; private set; } ///  /// Opens connection to MongoDB Server ///  public MongoDocumentsDatabase(String connectionString) { MongoUrl = MongoUrl.Create(connectionString); _databaseName = MongoUrl.DatabaseName; _client = new MongoClient(connectionString); } ///  /// Get database ///  public IMongoDatabase Database { get { return _client.GetDatabase(_databaseName); } } public IMongoCollection Zoo { get { return Database.GetCollection("zoo"); } } } class Program { static void Main(string[] args) { var connectionString = "mongodb://admin:admin@localhost:27017/testDatabase"; var pr = new Program(); pr.Save(connectionString); var zoo = pr.Get(connectionString); foreach (var animal in zoo.Animals) { Console.WriteLine(animal.Name + " " + animal.GetType()); } } public void Save(string connectionString) { var zoo = new Zoo { Animals = new List { new Tiger { Height = 1, Name = "Tiger1" }, new Zebra { Name = "Zebra1", StripesAmount = 100 } } }; var database = new MongoDocumentsDatabase(connectionString); database.Zoo.InsertOneAsync(zoo).Wait(); } public Zoo Get(string connectionString) { var database = new MongoDocumentsDatabase(connectionString); var task = database.Zoo.Find(e => true).SingleAsync(); task.Wait(); return task.Result; } } 

以下是对象存储在数据库中的方式(Robomongo) 在此处输入图像描述

最终结果: 在此处输入图像描述

非常感谢Anton Putau提供最简单的解决方案。

但还有另外一个。 要手动序列化对象:

 public class MyListAnimalSerializer : SerializerBase> { public override void Serialize(MongoDB.Bson.Serialization.BsonSerializationContext context, MongoDB.Bson.Serialization.BsonSerializationArgs args, List value) { context.Writer.WriteStartArray(); foreach (Animal mvnt in value) { context.Writer.WriteStartDocument(); switch (mvnt.GetType().Name) { case "Tiger": //your serialization here break; case "Zebra": //your serialization here break; default: break; } context.Writer.WriteEndDocument(); } context.Writer.WriteEndArray(); } public override List Deserialize(MongoDB.Bson.Serialization.BsonDeserializationContext context, MongoDB.Bson.Serialization.BsonDeserializationArgs args) { context.Reader.ReadStartArray(); List result = new List(); while (true) { try { //this catch block only need to identify the end of the Array context.Reader.ReadStartDocument(); } catch (Exception exp) { context.Reader.ReadEndArray(); break; } var type = context.Reader.ReadString(); var _id = context.Reader.ReadObjectId(); var name = context.Reader.ReadString(); if (type == "Tiger") { double tiger_height = context.Reader.ReadDouble(); result.Add(new Tiger() { Id = id, Name = animal_name, Height = tiger_height }); } else { long zebra_stripes = context.Reader.ReadInt64(); result.Add(return new Zebra() { Id = id, Name = animal_name, StripesAmount = zebra_stripes }); } context.Reader.ReadEndDocument(); } return result; } } 

只需要注释IEnumerable字段即可使用序列化程序:

 [BsonSerializer(typeof(MyListAnimalSerializer))] public List Animals { get; set; }