参考文章:
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的话要自己写序列化接口