參考文章:
1.http://blog.csdn.net/z69183787/article/details/26709505
2.https://blog.csdn.net/dai815904261/article/details/78919414
3.https://www.cnblogs.com/fengxuehuanlin/p/5700282.html
4.https://www.cnblogs.com/yanweidie/p/4605212.html
一、Bson和 Json的區別
BSON是由10gen開發的一個數據格式,是一種基於 JSON 的二進制序列化格式,用於 MongoDB 存儲文檔並進行遠程過程調用。BSON基於JSON格式,選擇JSON進行改造的原因主要是JSON的通用性及JSON的schemaless的特性。
BSON主要會實現以下三點目標:
(1)更快的遍歷速度
對JSON格式來說,太大的JSON結構會導致數據遍歷非常慢。在JSON中,要跳過一個文檔進行數據讀取,需要對此文檔進行掃描才行,需要進行麻煩的數據結構匹配,比如括號的匹配,而BSON對JSON的一大改進就是,它會將JSON的每一個元素的長度存在元素的頭部,這樣你只需要讀取到元素長度就能直接seek到指定的點上進行讀取了。
(2)操作更簡易
對JSON來說,數據存儲是無類型的,比如你要修改基本一個值,從9到10,由於從一個字符變成了兩個,所以可能其后面的所有內容都需要往后移一位才可以。而使用BSON,你可以指定這個列為數字列,那么無論數字從9長到10還是100,我們都只是在存儲數字的那一位上進行修改,不會導致數據總長變大。當然,在MongoDB中,如果數字從整形增大到長整型,還是會導致數據總長變大的。
(3)增加了額外的數據類型
JSON是一個很方便的數據交換格式,但是其類型比較有限。BSON在其基礎上增加了“byte array”數據類型。這使得二進制的存儲不再需要先base64轉換后再存成JSON。大大減少了計算開銷和數據大小。
但是,在有的時候,BSON相對JSON來說也並沒有空間上的優勢,比如對{“field”:7},在JSON的存儲上7只使用了一個字節,而如果用BSON,那就是至少4個字節(32位)
目前在10gen的努力下,BSON已經有了針對多種語言的編碼解碼包。並且都是Apache 2 license下開源的。並且還在隨着MongoDB進一步地發展。
BSON 支持的數據類型如表所示。
類型 | 描述示例 |
---|---|
NULL | 表示空值或者不存在的字段,{"x" : null} |
Boolean | 布爾型有 true 和 false,{"x" : true} |
Number | 數值:客戶端默認使用 64 位浮點型數值。{"x" : 3.14} 或 {"x" : 3}。對於整型值,包括 NumberInt(4 字節符號整數)或 NumberLong(8 字節符號整數),用戶可以指定數值類型,{"x" : NumberInt("3")} |
String | 字符串:BSON 字符串是 UTF-8,{"x" : "中文"} |
Regular Expression | 正則表達式:語法與 JavaScript 的正則表達式相同,{"x" : /[cba]/} |
Array | 數組:使用“[]”表示,{"x" : ["a", "b", "c"]} |
Object | 內嵌文檔:文檔的值是嵌套文檔,{"a" : {"b" : 3}} |
ObjectId | 對象 id:對象 id 是一個 12 字節的字符串,是文檔的唯一標識,{"x" : objectId()} |
BinaryData | 二進制數據:二進制數據是一個任意字節的字符串。它不能直接在 Shell 中使用。如果要將非 UTF-8 字符保存到數據庫中,二進制數據是唯一的方式 |
JavaScript | 代碼:查詢和文檔中可以包括任何 JavaScript 代碼,{"x" : function(){/*...*/}} |
Data | 日期:{"x" : new Date()} |
Timestamp | 時間戳:var a = new Timestamp() |
二、Json的序列化和反序列化
1.使用JavaScriptSerializer類:
//使用JavaScriptSerializer方式需要引入的命名空間,這個在程序集System.Web.Extensions.dll.中
using System.Web.Script.Serialization;
2.使用DataContractJsonSerializer類:
//實體中的特性[DataMember],[DataContract],是使用DataContractJsonSerializer序列化和反序列化必須要加的
//使用DataContractJsonSerializer方式需要引入的命名空間,在System.Runtime.Serialization.dll.中
using System.Runtime.Serialization.Json;
3.(推薦)使用Json.Net(即Newtonsoft.Json)類庫:
using Newtonsoft.Json;
反序列化:JsonConvert.DeserializeObject()
序列化:JsonConvert.SerializeObject()
Json.Net是支持序列化和反序列化DataTable,DataSet,Entity Framework和Entity的。序列化和反序列化常用到JsonSerializerSettings類進行設置
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 //序列化操作
6 var json = new { user = new { name = "fxhl", age = 23 }}; 7 string jsonData = JsonConvert.SerializeObject(json); 8 Console.WriteLine(jsonData); 9 //反序列化操作方法一
10 Person p1= JsonConvert.DeserializeObject<Person>(jsonData); 11 Console.WriteLine(p1.user.name); 12 //反序列化操作方法二
13 string json2 = "[{\"user\":{\"name\":\"fxhl\",\"age\":23}}]"; 14 List<Person> listp2= JsonConvert.DeserializeObject<List<Person>>(json2); 15 Console.WriteLine(listp2[0].user.name); 16 Console.ReadKey(); 17 } 18 } 19 public class Person 20 { 21 public Person user { get; set; } 22 public string name { get; set; } 23 public int age { get; set; } 24 }
三、Bson的序列化與反序列化
反序列化:BsonSerializer.Deserialize()
序列化:BsonExtensionMethods.ToJson()
四、高級用法
請點原文鏈接查看Newtonsoft.Json高級用法
1.使用特性實現特殊化處理
序列化和反序列化對象時,可以通過在字段和類上添加特性,實現特殊化處理
1.1 類特性
[BsonIgnoreExtraElements]:BsonSerializer時,忽略未匹配到i的字段,可避免在反序列化時會因為缺少_id字段而無法成功反序列化對象。
[JsonObject(MemberSerialization.OptIn)]
OptOut | 默認值,類中所有公有成員會被序列化,如果不想被序列化,可以用特性JsonIgnore |
OptIn | 默認情況下,所有的成員不會被序列化,類中的成員只有標有特性JsonProperty的才會被序列化,當類的成員很多,但客戶端僅僅需要一部分數據時,很有用 |
1.2字段特性
可以設置字段是否被忽略、默認值、null值處理和類型等等處理。下面僅列出一些常用特性:
1、[Newtonsoft.Json.JsonIgnore]特性:使用Newtonsoft.Json序列化時字段不會被序列化。 2、[System.Web.Script.Serialization.ScriptIgnore]特性:使用JavaScriptSerializer序列化時字段不會被序列化。 3、[System.Xml.Serialization.XmlIgnore]特性:字段不會被序列化成XML。
4、[BsonIgnore]特性:BsonSerializer時,字段不會被序列化。
5、[BsonElement]:自定義字段關聯的名稱和特殊處理
6、[JsonProperty]:自定義字段關聯的名稱和特殊處理
7、[BsonRepresentation]
2.采用JsonSerialzerSettings統一設置
JsonSerialzerSettings是JsonConvert方法中的參數,當所有字段做相同處理時,可直接配置在JsonSerialzerSettings中。
例如,json序列化時,如果時間類型中的毫秒是0,則在序列化時會被省略,
//設置不忽略時間的毫秒。
JsonSerializerSettings settings = new JsonSerializerSettings(); IsoDateTimeConverter dateConverter = new IsoDateTimeConverter { DateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.fff'Z'" }; settings.Converters.Add(dateConverter); string jsonStr = JsonConvert.SerializeObject(arr, settings); //反序列化設置 忽略不可匹配的項
var jSetting = new JsonSerializerSettings(); jSetting.NullValueHandling = NullValueHandling.Ignore; string devicejsonstr = FileHelper.GetContentFromFile(devicePath); device = JsonConvert.DeserializeObject<List<Device>>(devicejsonstr, jSetting);
3.JsonWriterSettings配置
把一個對象用BsonExtensionMethods.ToJson()方法得到的不是標准Json格式的字符串。本文開頭的表格中列出了Bson支持Value的類型。
默認輸出是Shell模式:整型是NumberLong(),Id是ObjectId(),DateTime是 ISODate("2019-12-23T07:41:09.397Z")。Strict模式: "_id" : { "$oid" : "5e0073335b0fd0502cb9ddef" }, "Date" : { "$date" : 1577087795171 }。可以使用如下方法改變Bson對象序列化時的輸出格式:
public class Test { public ObjectId Id { get; set; } public DateTime CreateDate { get; set; } public BsonDocument Data { get; set; } } var jsonWriterSettings = new JsonWriterSettings { OutputMode = JsonOutputMode.Strict }; string bsonStr = bsonObj.ToJson(jsonWriterSettings);
不同序列化方式結果輸出如下:
bson-Shell模式:{ "_id" : ObjectId("5e0075c4b2cde92970d12a47"), "CreateDate" : ISODate("2019-12-23T08:07:32.283Z"), "Data" : { "id" : 11 } } bson-Strict模式:{ "_id" : { "$oid" : "5e0075c4b2cde92970d12a47" }, "CreateDate" : { "$date" : 1577088452283 }, "Data" : { "id" : 11 } } json無配置:{"Id":"5e0075c4b2cde92970d12a47","CreateDate":"2019-12-23T16:07:32.2836112+08:00","Data":[{"Name":"id","Value":11}]}
可以明顯看出這三種類型的輸出都不符合Json標准格式,用Json反序列化Bson的結果或異常!
4.Bson序列化Dictionary
MongoDB C#驅動程序有三種序列化字典的方法:Document,ArrayOfArrays& ArrayOfDocuments(more on that in the docs)。默認是將字典序列化為文檔(Document),當它作為文檔序列化時,字典鍵是具有一些限制的BSON元素的名稱(例如,dictionary的key必須被串行化為字符串)
要更改此特定屬性的序列化,我們可以使用不同的DictionaryRepresentation的BsonDictionaryOptions屬性:
[BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)]
public Dictionary<DateTime, int> Dictionary { get; private set; }
但是,我們需要對每一個有問題的成員單獨做到這一點.要將此DictionaryRepresentation應用於所有相關成員,我們可以實現一個新的約定:
1 class DictionaryRepresentationConvention : ConventionBase, IMemberMapConvention 2 { 3 private readonly DictionaryRepresentation _dictionaryRepresentation; 4 public DictionaryRepresentationConvention(DictionaryRepresentation dictionaryRepresentation) 5 { 6 _dictionaryRepresentation = dictionaryRepresentation; 7 } 8 public void Apply(BsonMemberMap memberMap) 9 { 10 memberMap.SetSerializer(ConfigureSerializer(memberMap.GetSerializer())); 11 } 12 private IBsonSerializer ConfigureSerializer(IBsonSerializer serializer) 13 { 14 var dictionaryRepresentationConfigurable = serializer as IDictionaryRepresentationConfigurable; 15 if (dictionaryRepresentationConfigurable != null) 16 { 17 serializer = dictionaryRepresentationConfigurable.WithDictionaryRepresentation(_dictionaryRepresentation); 18 } 19 20 var childSerializerConfigurable = serializer as IChildSerializerConfigurable; 21 return childSerializerConfigurable == null 22 ? serializer 23 : childSerializerConfigurable.WithChildSerializer(ConfigureSerializer(childSerializerConfigurable.ChildSerializer)); 24 } 25 }
我們注冊如下:
ConventionRegistry.Register( "DictionaryRepresentationConvention", new ConventionPack {new DictionaryRepresentationConvention(DictionaryRepresentation.ArrayOfArrays)}, _ => true);
五、注意事項
1.Bson可以看作是Json的特異化,有相同點,也有很大的區別。所以再做序列化和反序列化時,代碼里最好一直用同一套,或者是用bson和json有嚴格的隔離,不要用着bson序列化,再用Json反序列化。
2.代碼內部轉換時,推薦使用Bson進行序列化和反序列化。因為如果類中存在BsonDocument類型的字段,Json會反序列化失敗!!
3.前后端交互時,推薦使用Json進行序列化和反序列化。由於前端一般用標准Json格式,用Bson的話要自己寫序列化接口