2015-05-24 5 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 Чтобы создать собственный сериализатор сбора данных для поля?

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

Ахаха! Большое спасибо! Я сделал ТОЧНО то же самое, и по некоторым причинам (я думаю, небольшая ошибка) не работал для меня! После твоего поста он начал работать)) Тем временем я написал другое решение для этой задачи. Я отправлю его ниже. Еще раз спасибо. Иван. –

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

Смежные вопросы