C#中如何將MongoDB->RunCommand結(jié)果映射到業(yè)務(wù)類的方法總結(jié)
前言
一直沒實(shí)際用過MongoDB,最近有個(gè)項(xiàng)目中用了用,踩了一些坑。這篇文章會(huì)介紹將MongoDB->RunCommand結(jié)果映射到業(yè)務(wù)類時(shí)碰到的問題,以及對(duì)各種方法的探索。
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#中運(yùn)行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有些不一樣,需要進(jìn)行映射。因?yàn)椴煌姆葱蛄谢椒ǎ捎玫姆绞揭矔?huì)不同,所以下面會(huì)有相關(guān)介紹。
使用Json.NET
因?yàn)镴son.NET用的比較多,基本思路就是用它來反序列化Bson,但是Json和Bson是不同的,不能用JsonConvert。
不過Json.NET提供了一個(gè)新的包Newtonsoft.Json.Bson來解析Bson數(shù)據(jù),并且提供了一個(gè)例子。
https://www.newtonsoft.com/json/help/html/DeserializeFromBson.htm
這個(gè)例子有點(diǎn)過時(shí)了,里邊用的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<Event>(reader);
Console.WriteLine(e.Name);
// Movie Premiere
}
看樣子有個(gè)byte數(shù)組就可以了,然后再看BsonDocument正好有個(gè)方法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<BsonDocument>(findCommand)
.GetElement("cursor").Value.ToBsonDocument()
.GetElement("firstBatch").ToBsonDocument()
.ToBson();
var personList = DeserializeBson<PersonList>(findResult);
數(shù)組不能是Bson的根元素,所以這里定義了一個(gè)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; }
}
這里還用了一個(gè) JsonConverter(typeof(ObjectIdConverter)) ,因?yàn)镺bjectId不能直接轉(zhuǎn)換為string,所以定義了一個(gè)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();
}
}
還有一個(gè)重要的方法,反序列化:
public static T DeserializeBson<T>(byte[] data)
{
MemoryStream ms = new MemoryStream(data);
using (BsonDataReader reader = new BsonDataReader(ms, false, DateTimeKind.Local))
{
JsonSerializer serializer = new JsonSerializer();
T e = serializer.Deserialize<T>(reader);
return e;
}
}
現(xiàn)在運(yùn)行程序看看吧:
但是感覺好復(fù)雜,過了一彎又一彎。
使用MongoDB .NET Driver內(nèi)置
話說這么常用的功能,SDK應(yīng)該內(nèi)置了才對(duì),何必舍近求遠(yuǎn),。
既然RunCommand可以傳遞一個(gè)類型,那么SDK應(yīng)該是支持反序列化自定義類型的。
嘗試根據(jù)返回的結(jié)果定義一個(gè)新的類:
[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<FindCommandResult>(findCommand);
代碼跑起來:
這個(gè)方式相比Json.NET更直接,更簡單。
使用查找賦值的方式
為了反序列化,適應(yīng)MongoDB,定義了一些沒有業(yè)務(wù)意義的類型,加了很多的屬性注解,感覺還不夠直接顯性。
也許只需要數(shù)據(jù)中的某幾個(gè)字段,或者根本就沒必要定義類型,只需要放到一個(gè)列表中。
又查看了BsonDocument的定義,發(fā)現(xiàn)可以在運(yùn)行命令時(shí)先反序列化為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<BsonDocument>(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();
運(yùn)行后直接返回List<PersonInfo> ,更貼近業(yè)務(wù)需求。
這是本文中最簡單的方式了。
如果做的更通用點(diǎn),可以在這里通過反射自動(dòng)實(shí)例化相關(guān)類型,不過這不如直接使用SDK內(nèi)置的反序列化方式了。
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對(duì)我們的支持。
上一篇:WinForm IP地址輸入框控件實(shí)現(xiàn)
欄 目:C#教程
下一篇:C#自定義IP輸入框控件
本文標(biāo)題:C#中如何將MongoDB-&gt;RunCommand結(jié)果映射到業(yè)務(wù)類的方法總結(jié)
本文地址:http://www.jygsgssxh.com/a1/C_jiaocheng/5192.html
您可能感興趣的文章
- 01-10C#通過反射獲取當(dāng)前工程中所有窗體并打開的方法
- 01-10C#實(shí)現(xiàn)Winform中打開網(wǎng)頁頁面的方法
- 01-10C#實(shí)現(xiàn)由四周向中心縮小的窗體退出特效
- 01-10Extjs4如何處理后臺(tái)json數(shù)據(jù)中日期和時(shí)間
- 01-10C#實(shí)現(xiàn)將窗體固定在顯示器的左上角且不能移動(dòng)的方法
- 01-10C#中DataGridView常用操作實(shí)例小結(jié)
- 01-10C#編程獲取資源文件中圖片的方法
- 01-10C#實(shí)現(xiàn)將程序鎖定到Win7任務(wù)欄的方法
- 01-10asp.net中XML如何做增刪改查操作
- 01-10C#利用反射技術(shù)實(shí)現(xiàn)去掉按鈕選中時(shí)的邊框效果


閱讀排行
本欄相關(guān)
- 01-10C#通過反射獲取當(dāng)前工程中所有窗體并
- 01-10關(guān)于ASP網(wǎng)頁無法打開的解決方案
- 01-10WinForm限制窗體不能移到屏幕外的方法
- 01-10WinForm繪制圓角的方法
- 01-10C#實(shí)現(xiàn)txt定位指定行完整實(shí)例
- 01-10WinForm實(shí)現(xiàn)仿視頻播放器左下角滾動(dòng)新
- 01-10C#停止線程的方法
- 01-10C#實(shí)現(xiàn)清空回收站的方法
- 01-10C#通過重寫Panel改變邊框顏色與寬度的
- 01-10C#實(shí)現(xiàn)讀取注冊(cè)表監(jiān)控當(dāng)前操作系統(tǒng)已
隨機(jī)閱讀
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 04-02jquery與jsp,用jquery
- 01-10C#中split用法實(shí)例總結(jié)
- 08-05織夢dedecms什么時(shí)候用欄目交叉功能?
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 01-11ajax實(shí)現(xiàn)頁面的局部加載
- 01-10delphi制作wav文件的方法
- 01-10使用C語言求解撲克牌的順子及n個(gè)骰子


