我有四个简单的课程
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对象存储在一个不同的集合中(&#34; animals&#34;)。
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; }
有人能举个例子吗? 提前致谢。
答案 0 :(得分: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: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)
最终结果:
答案 1 :(得分: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; }
答案 2 :(得分:2)
尝试反序列化的此实现。它将避免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;
}