2015-05-24 67 views
3

我有四个简单的类MongoDB的自定义集合串行

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; } 
} 

我创建了自定义序列化,让我存储在不同的收集动物对象(“动物”)。

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(); 

但我不能做同样的,当动物被保存在动物园 ,不能从动物园收集反序列化动物园:

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

它是pos sible为该字段创建自定义集合序列化程序?

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

任何人都可以举个例子吗? 在此先感谢。

回答

5

您是否访问过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:[email protected]: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) enter image description here

而最终的结果: enter image description here

+0

Ahaha!非常感谢你!我做了完全相同的事情,并且出于某种原因(我认为有一点小错误)并不适合我!之后,它开始工作))同时,我为这项任务写了另一个解决方案。我会在下面发布。 再次感谢。伊万。 –

4

非常感谢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; } 
+0

也许可以删除try catch并替换为:if(IsAtEndOfFile)(http://api.mongodb.com/csharp/current/html/M_MongoDB_Bson_IO_IBsonReader_IsAtEndOfFile.htm – solvingJ