【问题标题】:MongoDb custom collection serializerMongoDb 自定义集合序列化器
【发布时间】:2015-08-05 22:24:01
【问题描述】:

我有四个简单的类

public class Zoo{
    public ObjectId Id { get; set; } 
    public List<Animal> 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 对象存储在不同的集合(“动物”)中。

class MyAnimalSerializer : SerializerBase<Animal>
{
    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<Animal> collection = db.GetCollection<Animal>("animals");
var lst = await collection.Find<Animal>(new BsonDocument()).ToListAsync();

但我不能这样做,当动物被存放在动物园中 并且无法从 Zoo 集合中反序列化 Zoo:

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

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

public List<Animal> Animals { get; set; }

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

【问题讨论】:

    标签: c# mongodb serialization


    【解决方案1】:

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

    但是还有一个。手动序列化对象:

    public class MyListAnimalSerializer : SerializerBase<List<Animals>>
    {
        public override void Serialize(MongoDB.Bson.Serialization.BsonSerializationContext context, MongoDB.Bson.Serialization.BsonSerializationArgs args, List<Animal> 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<Animals> Deserialize(MongoDB.Bson.Serialization.BsonDeserializationContext context, MongoDB.Bson.Serialization.BsonDeserializationArgs args)
        {
            context.Reader.ReadStartArray();
    
            List<Animals> result = new List<Animals>();
    
            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<Animal> Animals { get; set; }
    

    【讨论】:

    【解决方案2】:

    您访问过这个document 页面吗?还有多态类的例子。

    这是我存储对象的示例:

    public class Zoo
    {
        [BsonId]
        public ObjectId Id { get; set; }
        public List<Animal> 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
    {
        /// <summary>
        /// MongoDB Server
        /// </summary>
        private readonly MongoClient _client;
    
        /// <summary>
        /// Name of database 
        /// </summary>
        private readonly string _databaseName;
    
        public MongoUrl MongoUrl { get; private set; }
    
        /// <summary>
        /// Opens connection to MongoDB Server
        /// </summary>
        public MongoDocumentsDatabase(String connectionString)
        {
            MongoUrl = MongoUrl.Create(connectionString);
            _databaseName = MongoUrl.DatabaseName;
            _client = new MongoClient(connectionString);
        }
    
        /// <summary>
        /// Get database
        /// </summary>
        public IMongoDatabase Database
        {
            get { return _client.GetDatabase(_databaseName); }
        }
        public IMongoCollection<Zoo> Zoo { get { return Database.GetCollection<Zoo>("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<Animal>
                {
                    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)

    最终结果:

    【讨论】:

    • 啊哈哈!非常感谢!我做了完全相同的事情,但由于某些原因(我认为是一个小错误)对我没有用!在你的帖子之后它开始工作))同时我为这个任务写了另一个解决方案。我将在下面发布。再次感谢。伊万。
    【解决方案3】:

    试试这个反序列化的实现。它将避免 try ... catch 实现。

    public override List<Animals> Deserialize(MongoDB.Bson.Serialization.BsonDeserializationContext context, MongoDB.Bson.Serialization.BsonDeserializationArgs args)
    {
        context.Reader.ReadStartArray();
        context.Reader.ReadBSonType();
    
        List<Animals> result = new List<Animals>();
    
        while (context.Reader.State != MongoDB.Bson.IO.BsonReaderState.EndOfArray)
        {
            context.Reader.ReadStartDocument();
    
            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();
            context.Reader.ReadBsonType();
        }
    
        context.Reader.ReadEndArray();
    
        return result;
    }
    

    【讨论】:

      猜你喜欢
      • 2017-06-23
      • 2012-11-29
      • 1970-01-01
      • 2016-10-28
      • 2019-03-20
      • 1970-01-01
      • 1970-01-01
      • 2018-01-25
      • 2018-04-07
      相关资源
      最近更新 更多