2015-05-24 62 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