MongoDB学习(翻译5)

C#驱动序列化文档对象

介绍

本文档基于C#官方驱动1.8版本。数据库

本节C#驱动教程谈论C#类到BSON对象的序列化和反序列化。序列化是映射一个对象到可保存到MongoDB库中BSON对象的过程,反序列化由BSON文档重建对象的逆过程。所以,序列化过程一般被称为“对象映射”数组

序列化使用BSON库处理。BSON库拥有一个可扩展的序列化结构,因此你能够控制你的序列化方式。BSON库提供的默认的序列化其能够知足你大部分的需求,若是你须要特殊处理,你能够对其进行扩展。函数

默认序列化器经过“类映射”来处理。类映射是定义类和BSON文档对象间映射的一种结构,它包含一系列参与序列化的字段或属性而且为每个定义了所需的序列化参数(例如,BSON元素名,表明选项等)。spa

默认的序列化器也内建了对.NET数据类型(原始类型、数组、集合、字典等)的支持。code

序列化一个类对象以前,该类映射必须存在,能够手动建立类映射也能够简单的经过自动映射来建立。你能够在类自动映射的过程当中经过使用序列化相关特性或者初始化代码的方式施加一些控制。对象

建立类映射

在你的初始化代码中建立类映射:blog

BsonClassMap.RegisterClassMap<MyClass>();

 

在此MyClass 会被自动映射或者注册,固然你可让你的类经过序列化器自动映射。教程

若是你想控制建立的类映射,你能够在一个lambda表达式中提供您本身的初始化代码:事件

 

BsonClassMap.RegisterClassMap<MyClass)(cm => {

    cm.MapProperty(c => c.SomeProperty);

    cm.MapProperty(c => c.AnotherProperty);

});

 

当lambda表达式执行“CM”(简称类映射),参数传递一个空类映射供您填充。在本例子中两个属性经过调用MapProperty 方法被添加进去,传进MapProperty 的参数是它们自己。使用lambda表达式,而不是仅仅使用一个字符串参数的属性名称的优势是IntelliSense和编译时检查,确保你正确的拼写属性名称。ip

另外,也可使用自动映射,而后覆写一些结果。稍后咱们将会看到这方面的例子。

注意类映射必须只能被注册一次(若是你试着屡次注册同一个类,会抛出异常)。

一般状况,你能够在只执行一次的代码路径中调用RegisterClassMap (Main 方法,Application_Start 事件等),若是你在执行次数多于一次的代码路径中调用RegisterClassMap 方法,你也能够经过调用IsClassMapRegistered 来检查该类是否被注册过:

if (!BsonClassMap.IsClassMapRegistered(typeof(MyClass))) {

   // 为MyClass注册类映射

}

 

Creator Maps

默认状况下,类一定包括一个无参的构造函数来用于类的实例化,而后配置一个具备和映射属性相关的参数的构造函数是能够的,有两种方法能够实现:

使用一个表达式,你能够按照下面方式经过驱动使用一个creator map

public class Person

{

  public string FirstName { get; private set; }

  public string LastName { get; private set; }

 

  public Person(string firstName, string lastName)

  {

    FirstName = firstName;

    LastName = lastName;

  }

}



BsonClassMap.RegisterClassMap<Person>(cm =>

{

    cm.AutoMap();

    cm.MapCreator(p => new Person(p.FirstName, p.LastName));

});

 

解析表达式树使构造函数第一个参数和FirstName 相关,使构造函数第二个参数和LastName 属性相关。还有其余更复杂的方式处理这种状况,当须要时,能够研究探索。

经过特性:

public class Person

{

  public string FirstName { get; set; }

  public string LastName { get; set; }

 

  [BsonConstructor]

  public Person(string firstName, string lastName)

  {

    FirstName = firstName;

    LastName = lastName;

  }

}

 

当不止一个构造函数是,咱们经过“知足大多数参数”这一策略来肯定哪一个是最好的匹配,例如:

public class Person

{

  public string FirstName { get; set; }

  public string LastName { get; set; }

  public DateTime? BirthDate { get; set; }

 

  [BsonConstructor]

  public Person(string firstName, string lastName)

  {

    // snip...

  }

 

  [BsonConstructor]

  public Person(string firstName, string lastName, DateTime birthDate)

  {

    // snip...

  }

}

 

若是数据库中文档对象有一个BirthDate字段,咱们会选择使用包含3个参数的构造函数,由于它更具体。

除了上面代码和属性的形式,映射一建立者能够经过约定(约束)来处理。

约定(约束)

自动进行类映射有许多须要考虑的方面,例如

. 例如

  • 哪一个字段或属性应该被序列化
  • 哪一个字段或属性是ID列
  • 什么元素名称能够被用在BSON文档中
  • 若是是多态,怎么肯定使用哪一个
  • 若是咱们没法识别一个BSON文档中包含的元素会如何
  • 字段或属性是否有一个默认值
  • 默认值应该被序列化仍是被忽略
  • null 值应该被序列化仍是被忽略

这些问题的答案就表明一组约定。对于每个约定都有一个默认的惯例,它是最有可能被您使用的一个,在必要时也能够从新个别约定(甚至写你本身的)。

若是你想使用和默认约定不一样的本身的约定,能够很简单的建立一个ConventionPack 的实例,添加你想使用的约定进去,而后注册(换句话说,当你使用具体约定的时候通知序列化器)。例如:

var myConventions = new ConventionPack();

pack.Add(new CamelCaseElementNameConvention());

 

ConventionRegistry.Register(

   "My Custom Conventions",

   pack,

   t => t.FullName.StartsWith("MyNamespace."));

 

第三个参数是用来定义什么时候使用这个约定包的过滤器方法。在这种状况下,也就是指若是任何类的全名以MyNamespace开头的话应该使用myConventions约定。

由上面咱们已经了解到,除了预约的约定(约束),你能够自定义本身的约定(约束)。有4个可让咱们建立和注册自定义约定的类,运行在不一样(阶段)级别。

  1. 类(阶段)级别IClassMapConvention

运行针对类映射阶段.

  1. 方法(成员) 级别(阶段)IMemberMapConvention

运行针对在IClassMapConvention 阶段发现映射的每名成员

  1. Creator 阶段ICreatorMapConvention

运行针对在IClassMapConvention 阶段发现映射的CreatorMap

 

  1. 后期处理阶段: IPostProcessingConvention

运行针对类映射阶段.

 

约定在他们注册的每一个阶段顺序运行,默认的约定会先注册,这就容许任何用户注册的约定覆盖掉默认的约定。因此某些值可能获得应用和覆写,这就要求用户确保注册顺序的正确性。

注意:

 

若是一个IPostProcessingConvention 的自定义实现的注册早于一个IClassMapConvention的自定义实现,那么IClassMapConvention 先运行,由于它是运行类阶段是早于后处理阶段的。

 

待续。。。。

下篇介绍:

Field or Property Level Serialization Options

相关文章
相关标签/搜索