這篇文章將為大家詳細(xì)講解有關(guān)C#中怎么將MongoDB->RunCommand結(jié)果映射到業(yè)務(wù)類,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
創(chuàng)新互聯(lián)建站專業(yè)為企業(yè)提供豐順網(wǎng)站建設(shè)、豐順做網(wǎng)站、豐順網(wǎng)站設(shè)計、豐順網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計與制作、豐順企業(yè)網(wǎng)站模板建站服務(wù),10年豐順做網(wǎng)站經(jīng)驗,不只是建網(wǎng)站,更提供有價值的思路和整體網(wǎng)絡(luò)服務(wù)。
前言
一直沒實際用過MongoDB,最近有個項目中用了用,踩了一些坑,具體內(nèi)容如下:
Collection中的數(shù)據(jù)是這樣的:
使用find命令查詢數(shù)據(jù):
db.runCommand({"find":"test", limit:2, sort:{AddTime:-1}})
查詢返回的數(shù)據(jù)結(jié)構(gòu)是這樣的,需要的數(shù)據(jù)在firstBatch中:
{ "cursor" : { "firstBatch" : [ { "_id" : ObjectId("5ad0042944fd3929db6b869f"), "Name" : "李四", "AddTime" : ISODate("2018-04-12T01:13:18.965Z") }, { "_id" : ObjectId("5ad003e844fd3929db6b869e"), "Name" : "張三", "AddTime" : ISODate("2018-04-02T01:11:18.965Z") } ], "id" : NumberLong(0), "ns" : "test.test" }, "ok" : 1.0 }
下面將在C#中運行find命令來執(zhí)行查詢,并將結(jié)果映射到自定義的PersonInfo類。
private class PersonInfo { public string Id { get; set; } public string Name { get; set; } public DateTime AddTime { get; set; } }
需要注意PersonInfo中的屬性Id和Document中的名稱_id有些不一樣,需要進行映射。因為不同的反序列化方法,采用的方式也會不同,所以下面會有相關(guān)介紹。
使用Json.NET
因為Json.NET用的比較多,基本思路就是用它來反序列化Bson,但是Json和Bson是不同的,不能用JsonConvert。
不過Json.NET提供了一個新的包Newtonsoft.Json.Bson
來解析Bson數(shù)據(jù),并且提供了一個例子。
https://www.newtonsoft.com/json/help/html/DeserializeFromBson.htm
這個例子有點過時了,里邊用的BsonReader我已替換為BsonDataReader。
byte[] data = Convert.FromBase64String("MQAAAAJOYW1lAA8AAABNb3ZpZSBQcmVtaWVyZQAJU3RhcnREYXRlAMDgKWE8AQAAAA=="); MemoryStream ms = new MemoryStream(data); using (BsonDataReader reader = new BsonDataReader(ms)) { JsonSerializer serializer = new JsonSerializer(); Event e = serializer.Deserialize(reader); Console.WriteLine(e.Name); // Movie Premiere }
看樣子有個byte數(shù)組就可以了,然后再看BsonDocument正好有個方法ToBson,獲取到的就是byte[]。
思路:先將RunCommand的結(jié)果映射為BsonDocument,然后查找到firstBatch,然后將其ToBson,然后使用Newtonsoft.Json.Bson
反序列化。
一切看起來很easy!
馬上碼起來:
var findCommand = BsonDocument.Parse("{\"find\":\"test\", limit:2, sort:{AddTime:-1}}"); var findResult = database.RunCommand(findCommand) .GetElement("cursor").Value.ToBsonDocument() .GetElement("firstBatch").ToBsonDocument() .ToBson(); var personList = DeserializeBson (findResult);
數(shù)組不能是Bson的根元素,所以這里定義了一個PersonList類:
private class PersonList { public string Name { get; set; } [JsonProperty(PropertyName = "Value")] public PersonInfo[] List { get; set; } }
需要注意的是上邊代碼中 GetElement(“firstBatch”).ToBsonDocument()
返回的數(shù)據(jù)格式是這樣的:
這里用了JsonProperty將Value映射為List。
還有Person類中的屬性名稱和document中的也有不同,也需要映射:
private class PersonInfo { [JsonProperty(PropertyName = "_id")] [JsonConverter(typeof(ObjectIdConverter))] public string Id { get; set; } public string Name { get; set; } public DateTime AddTime { get; set; } }
這里還用了一個 JsonConverter(typeof(ObjectIdConverter))
,因為ObjectId不能直接轉(zhuǎn)換為string,所以定義了一個ObjectIdConverter類:
public class ObjectIdConverter : JsonConverter { public override bool CanConvert(Type objectType) { return objectType == typeof(ObjectId); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { if (reader.Value != null) { var value = (byte[])reader.Value; var result = BitConverter.ToString(value).Replace("-", string.Empty).ToLowerInvariant(); return result; } return string.Empty; } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new NotImplementedException(); } }
還有一個重要的方法,反序列化:
public static T DeserializeBson(byte[] data) { MemoryStream ms = new MemoryStream(data); using (BsonDataReader reader = new BsonDataReader(ms, false, DateTimeKind.Local)) { JsonSerializer serializer = new JsonSerializer(); T e = serializer.Deserialize (reader); return e; } }
現(xiàn)在運行程序看看吧:
但是感覺好復(fù)雜,過了一彎又一彎。
使用MongoDB .NET Driver內(nèi)置
話說這么常用的功能,SDK應(yīng)該內(nèi)置了才對,何必舍近求遠,。
既然RunCommand可以傳遞一個類型,那么SDK應(yīng)該是支持反序列化自定義類型的。
嘗試根據(jù)返回的結(jié)果定義一個新的類:
[BsonIgnoreExtraElements] private class FindCommandResult { [BsonElement("cursor")] public ResultCursor Cursor { get; set; } } [BsonIgnoreExtraElements] private class ResultCursor { [BsonElement("firstBatch")] public PersonInfo[] Batch { get; set; } } private class PersonInfo { [BsonId] [BsonRepresentation(BsonType.ObjectId)] public string Id { get; set; } public string Name { get; set; } public DateTime AddTime { get; set; } }
BsonIgnoreExtraElements、BsonElement、BsonId、BsonRepresentation這些都是SDK內(nèi)置的Attribute,相關(guān)作用大家應(yīng)該能夠一目了然。
再看看查詢這塊的代碼:
var findCommand = BsonDocument.Parse("{\"find\":\"test\", limit:1, sort:{AddTime:-1}}"); var findResult = database.RunCommand(findCommand);
代碼跑起來:
這個方式相比Json.NET更直接,更簡單。
使用查找賦值的方式
為了反序列化,適應(yīng)MongoDB,定義了一些沒有業(yè)務(wù)意義的類型,加了很多的屬性注解,感覺還不夠直接顯性。
也許只需要數(shù)據(jù)中的某幾個字段,或者根本就沒必要定義類型,只需要放到一個列表中。
又查看了BsonDocument的定義,發(fā)現(xiàn)可以在運行命令時先反序列化為BsonDocument,然后再根據(jù)返回的數(shù)據(jù)結(jié)構(gòu)使用GetElement獲取相關(guān)字段的值。
代碼如下:
var findCommand = BsonDocument.Parse("{\"find\":\"test\", limit:2, sort:{AddTime:-1}}"); var findResult = database.RunCommand(findCommand) .GetElement("cursor").Value.ToBsonDocument() .GetElement("firstBatch").Value.AsBsonArray.Select(d => { var dbd = d.AsBsonDocument; return new PersonInfo() { Id = dbd.GetElement("_id").Value.AsObjectId.ToString(), AddTime = dbd.GetElement("AddTime").Value.ToLocalTime(), Name = dbd.GetElement("Name").Value.ToString(), }; }).ToList();
運行后直接返回List
,更貼近業(yè)務(wù)需求。
這是本文中最簡單的方式了。
如果做的更通用點,可以在這里通過反射自動實例化相關(guān)類型,不過這不如直接使用SDK內(nèi)置的反序列化方式了。
關(guān)于“C#中怎么將MongoDB->RunCommand結(jié)果映射到業(yè)務(wù)類”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,使各位可以學(xué)到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。