[英]C# MongoDB complex class serialization
我正在使用C#MongoDB驅動程序,我有這個相當復雜的JSON結構來保存:
{
"name" : "value",
"age": 1,
"isFemale": true,
"Hobbies" : {
//All data within the "Hobbies" node is dynamic
//and may change from one item to another.
"stringItem" : "value",
"intItem" : 0.0,
"listOfItems" : [
{ "field" : 1696.0 }
],
"intArray" : [ 566.0, 1200.0 ]
},
"Collection" : [
//All data within the "Collection" node is dynamic
//and may change from one item to another.
{
"field" : "string",
"FieldTypeId" : 2.0,
"array" : [
{ "value" : "1024x1000" }
]
}
]
}
我有這個代表上述對象的類:
public class MyClass
{
public string Name;
public int Age;
public bool IsFemale;
public Dictionary<string, object> Hobbies;
public List<Dictionary<string, object>> Collection;
}
以下是我為“愛好”部分保存的內容:
"Hobbies": {
"stringItem": "value",
"intItem": 1,
"listOfItems": {
"_t": "Newtonsoft.Json.Linq.JArray, Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed",
"_v": [{
"_t": "JObject",
"_v": [{
"_t": "JProperty",
"_v": [{
"_t": "JValue",
"_v": []
}]
},
{
"_t": "JProperty",
"_v": [{
"_t": "JValue",
"_v": []
}]
}]
}]
}
}
我的猜測是我應該為該類編寫自定義序列化程序,但我在MONGODB .NET DRIVER手冊中找不到任何有用的示例
我試圖開始並實現這樣的事情:
public class MyClassSerializer : SerializerBase<MyClass>, IBsonDocumentSerializer
{
public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, MyClass value)
{
//What to do here???
base.Serialize(context, args, value);
}
public override MyClass Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
//What to do here???
return base.Deserialize(context, args);
}
public bool TryGetMemberSerializationInfo(string memberName, out BsonSerializationInfo serializationInfo)
{
switch (memberName)
{
case "Name":
serializationInfo = new BsonSerializationInfo(memberName, new StringSerializer(), typeof(string));
return true;
case "Age":
serializationInfo = new BsonSerializationInfo(memberName, new Int16Serializer(), typeof(string));
return true;
case "IsFemale":
serializationInfo = new BsonSerializationInfo(memberName, new BooleanSerializer(), typeof(string));
return true;
case "Hobbies":
serializationInfo = new BsonSerializationInfo(memberName, new TupleSerializer<string, object>(), typeof(string));
return true;
case "Collection":
serializationInfo = new BsonSerializationInfo(memberName, new ArraySerializer<Dictionary<string, object>>(), typeof(string));
return true;
default:
serializationInfo = null;
return false;
}
}
}
但我找不到與此有關的任何事情。 它沒有完全實現,我讀到我需要在某個地方注冊序列化器,但在哪里......?
在這里找到了如何將數據保存到MongoDB: Dictionary-to-BsonDocument轉換省略了_t字段並將其擴展了一點,所以我想分享完整的解決方案。
第1步:
在我的課上,我為每個值聲明了2個成員:
// For the Hobbies object type:
[BsonIgnore] //ignore this value in MongoDB
public Dictionary<string, object> Hobbies { get; set; }
[JsonIgnore] //ignore this value in the response on Get requests
[BsonElement(elementName: "Hobbies")]
public BsonDocument HobbiesBson { get; set; }
/*********************************************************************/
// For the Collection object type:
[BsonIgnore] //ignore this value in MongoDB
public List<Dictionary<string, object>> Collection { get; set; }
[JsonIgnore] //ignore this value in the response on Get requests
[BsonElement(elementName: "Collection")]
public BsonArray CollectionBson { get; set; }
第2步
在我的WebAPI控制器的方法Post
[HttpPost]
public override async Task<IActionResult> Post([FromBody] Person person)
{
var jsonDoc = JsonConvert.SerializeObject(person.Hobbies);
person.HobbiesBson = BsonSerializer.Deserialize<BsonDocument>(jsonDoc);
jsonDoc = JsonConvert.SerializeObject(person.Collection);
person.CollectionBson = BsonSerializer.Deserialize<BsonArray>(jsonDoc);
//save
}
第3步
在我的Get
請求中,我將其反序列化為:
[HttpGet("{id?}")]
public override async Task<IActionResult> Get(string id = null)
{
var people = //get data from mongoDB
foreach (var person in people)
{
var bsonDoc = BsonExtensionMethods.ToJson(person.HobbiesBson);
person.Hobbies = JsonConvert.DeserializeObject<Dictionary<string, object>>(bsonDoc);
bsonDoc = BsonExtensionMethods.ToJson(person.CollectionBson);
person.Collection = JsonConvert.DeserializeObject<List<Dictionary<string, object>>>(bsonDoc);bsonDoc);
}
return Ok(people);
}
這解決了我的問題,我希望它也可以幫助其他人:-)
處理此問題而不必創建其他屬性的簡單方法是注冊自定義序列化程序。
ComplexTypeSerializer.cs
namespace MyNamespace.MongoDB.Serializers
{
public class ComplexTypeSerializer : SerializerBase<object>
{
public override object Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
var serializer = BsonSerializer.LookupSerializer(typeof(BsonDocument));
var document = serializer.Deserialize(context, args);
var bsonDocument = document.ToBsonDocument();
var result = BsonExtensionMethods.ToJson(bsonDocument);
return JsonConvert.DeserializeObject<IDictionary<string, object>>(result);
}
public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value)
{
var jsonDocument = JsonConvert.SerializeObject(value);
var bsonDocument = BsonSerializer.Deserialize<BsonDocument>(jsonDocument);
var serializer = BsonSerializer.LookupSerializer(typeof(BsonDocument));
serializer.Serialize(context, bsonDocument.AsBsonValue);
}
}
}
並根據http://mongodb.github.io/mongo-csharp-driver/2.3/reference/bson/serialization/注冊
BsonSerializer.RegisterSerializer(typeof(IDictionary<string, object>), new ComplexTypeSerializer());
要么
BsonSerializer.RegisterSerializer(typeof(IList<IDictionary<string, object>>), new ComplexTypeSerializer());
下面的代碼使用簡單的IDictionary<string, object>
進行測試,不確定它是否適用於IList<IDictionary<string, object>>
,但是如果它不受支持,則可以創建另一個自定義序列化程序來支持它。
嘗試在Serializer Registry部分( http://mongodb.github.io/mongo-csharp-driver/2.4/reference/bson/serialization/#serializer-registry )中更仔細地閱讀文檔:
序列化程序注冊表包含已注冊的所有IBsonSerializer。 它可以通過靜態類BsonSerializer的SerializerRegistry屬性訪問。
要注冊序列化器,請使用其中一個
BsonSerializer.RegisterSerializer(Type, IBsonSerializer)
要么
BsonSerializer.RegisterSerializer<T>(IBsonSerializer<T>)
這會將它們添加到
BsonSerializer.SerializerRegistry
在這里查看這些類的API - http://mongodb.github.io/mongo-csharp-driver/2.4/apidocs/html/T_MongoDB_Bson_Serialization_BsonSerializer.htm
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.