C#使用MongoDB-第二章 序列化

这篇具有很好参考价值的文章主要介绍了C#使用MongoDB-第二章 序列化。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

类型映射

这里在C#中所使用的连接MongoDB数据库的依赖库为MongoDB.Driver,使用前先到Nuget中进行安装。
C#使用MongoDB-第二章 序列化,C#操作数据库,c#,mongodb,开发语言

默认情况下,在我们对MongoDB数据库进行CRUD时,MongoDB.Driver(以后简称驱动库)会自动为我们根据属性、属性类型,将实体类型转换为对应的BSON。

  • 实体类

    public class Clothing
    {
        public ObjectId Id { get; set; }
        public string Name { get; set; }
        public bool InStock { get; set; }
        public double Price { get; set; }
        public List<string> ColorSelection { get; set; }
    }
    
  • 对应的BSON

    {
      "_id": ObjectId("..."),
      "Name": "Long Sleeve Shirt",
      "InStock": true,
      "Price": 17.99,
      "ColorSelection": [ "black", "navy", "red" ]
    }
    

一、常用特性与类型映射器配置

1、主键Id

默认情况下,驱动映射器将任何名为Idid_id的公共属性映射为BSON的_id字段。如果要显式选择要映射到_id字段的属性,可以使用[BsonId]特性。

  • 注意,如果自己指定_id字段,那么实体类中不能再包含Id_id属性。而且,[BsonId]只能使用在一个属性上。
  • Id属性建议使用ObjectId或者GUID类型,这样在存储数据时MongoDB会自动为我们维护唯一的ID,我们不用操心。
public class House
{
    [BsonId]
    public ObjectId Identifier { get; set; }
}

2、只读属性的处理

驱动库的自动映射器不会包含实体类中的只读属性,如果我们希望类中的只读属性在存储数据时候也一起作为数据字段存储到数据库中,那么可以有两种方式进行处理。

方式一使用[BsonElement]特性

在该属性上使用[BsonElement]特性。

  • 实体类

    public class Clothing
    {
        public ObjectId Id { get; set; }
        public string Name { get; set; }
        public bool InStock { get; set; }
        public double Price { get; set; }
        public List<string> ColorSelection { get; set; }
        [BsonElement]
        public int Upc { get; }
    }
    

方式二:注册类型映射器

  • 注册

    BsonClassMap.RegisterClassMap<Clothing>(classMap =>
    {
        classMap.AutoMap(); //这里表示其他属性按照默认的自动序列化
        classMap.MapProperty(c => c.Upc);
    });
    

注意

  • 由于该属性只读,所以可以进行序列化后存入数据库中,但是却无法在查询后进行反序列化。
  • 类型映射器的注册建议在行初始化MongoDB连接时进行。

3、字段名称设置

默认情况下,会将属性名称作为数据库字段名保存,如果想要设置别的字段名,可以使用[BsonElement("fieldName")]进行设置。

public class House
{
    public Guid Id { get; set; }

    [BsonElement("year_built")]
    public int YearBuilt { get; set; }
}

4、类型设置

如果要将C#属性的类型转为对应的BSON类型,可以使用[BsonRepresentation(type)]特性,需要注意的是,这只在C#基本类型可以转为指定的BSON类型时才有效。驱动库已经为我们提供了BsonType枚举里面定义了BSON的各种类型。

public class House
{
    public Guid Id { get; set; }
    [BsonRepresentation(BsonType.Int32)]
    public char YearBuilt { get; set; }
}

5、字段排序

默认情况下,会根据实体类的字段顺序进行映射保存,如果想要指定属性在数据库中的字段顺序,可以通过[BsonElement(Order = index)]来指定。

public class House
{
    public Guid Id { get; set; }
    [BsonElement(Order = 2)]
    public int YearBuilt { get; set; }
    [BsonElement(Order = 1)]
    public string Style { get; set; }
}

6、忽略属性

直接忽略属性

如果希望忽略实体类中的某个属性,在存储时候不进行序列化和数据存储,可以在属性上使用[BsonIgnore]特性。

  • 示例

    public class House
    {
        public Guid Id { get; set; }
        [BsonIgnore]
        public int YearBuilt { get; set; }
        public string Style { get; set; }
    }
    

忽略默认值属性

如果希望属性在使用默认值时(也就是属性没有进行赋值时),映射器忽略掉该属性,可以使用[BsonIgnoreIfDefault]特性

  • 示例

    public class House
    {
        public Guid Id { get; set; }
        [BsonIgnoreIfDefault]
        public int YearBuilt { get; set; }
    }
    

这里也可以使用注册类型映射器的方式

  • 示例

    BsonClassMap.RegisterClassMap<House>(classMap =>
    {
       classMap.AutoMap();//这里表示其他属性按照默认的自动序列化
       classMap.MapMember(h => h.YearBuilt).SetIgnoreIfDefault(true);
    });
    

7、默认值

默认情况下,在进行反序列化时,从数据库中如果找不到我们实体类某个属性的对应字段(这里是直接找不到,不存在该字段)时,会直接给该属性赋值对应类型的默认值,如果希望进行默认值的设置,可以通过两种方法来实现。

  • 注意,这里是反序列化的过程中设置默认值,而不是往数据库保存数据库的过程。

方式一使用[BsonDefaultValue(value)]特性

  • 示例

    public class House
    {
        public Guid Id { get; set; }
    
        [BsonDefaultValue(1900)]
        public int YearBuilt { get; set; }
    }
    

方式二:注册类型映射器

  • 示例

    BsonClassMap.RegisterClassMap<House>(classMap =>
    {
       classMap.AutoMap();//这里表示其他属性按照默认的自动序列化
       classMap.MapMember(h => h.YearBuilt).SetDefaultValue(1900);
    });
    

结合使用[BsonDefaultValue(value)][BsonIgnoreIfDefault]

可以巧妙的通过结合使用[BsonDefaultValue(value)][BsonIgnoreIfDefault]特性,来实现指定忽略指定值属性的效果。使用后发现,这样结合使用,对保存数据时能起效果。

  • 示例

    下例子中,当YearBuilt属性为1900时,就会忽略该属性

    public class House
    {
        public Guid Id { get; set; }
        [BsonDefaultValue(1900)]
        [BsonIgnoreIfDefault]
        public int YearBuilt { get; set; }
    }
    

8、时间字段的处理

如果我们的实体类中包含DateTime类型的属性,在进行数据保存时,映射器会对该属性自动进行时区的转换处理转为UTC时间。而我们可以通过[BsonDateTimeOptions]特性设置在进行反序列化时,时间数据以什么形式展示。

只包含日期

如果我们的DateTime属性只包含日期,而不包含时间,可以直接使用[BsonDateTimeOptions(DateOnly = true)]特性,让映射器不对该属性进行时区的转换处理。

  • 注意,此时不能直接赋值DateTime.Now,而是要用DateTime.Now.Date,主要是不要让属性含有时间,否则转换时会报错。

  • 示例

    public class PatientRecord
    {
        public Guid Id { get; set; }
        [BsonDateTimeOptions(DateOnly = true)]
        public DateTime DateOfBirth { get; set; } = DateTime.Now.Date;
    }
    

包含时间

如果DateTime属性包含了时间,由于保存到MongoDB时会转换为UTC时间,所以需要使用[BsonDateTimeOptions(Kind = DateTimeKind.Local)]让驱动库在进行反序列化时,将时间转换为本地时间。

  • 示例

    public class PatientRecord
    {
        public Guid Id { get; set; }
        [BsonDateTimeOptions(Kind = DateTimeKind.Local)]
        public DateTime AppointmentTime { get; set; }
    }
    

9、忽略额外字段

在驱动库进行反序列化时,会将核对文档的字段与类型的属性,如果文档中出现了在类型中找不到对应属性的字段,默认情况下会直接抛出异常。

如果希望在反序列化时,忽略数据库中的额外字段,只映射类中属性对应的字段,可以通过两种方式来实现。

方式一:对类型使用[BsonIgnoreExtraElements]特性

  • 示例

    [BsonIgnoreExtraElements]
    public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public List<string> Hobbies {get; set;}
    }
    

方式一:注册类型映射器

  • 示例

    BsonClassMap.RegisterClassMap<Person>(classMap =>
    {
         classMap.AutoMap();//这里表示其他属性按照默认的自动序列化
         classMap.SetIgnoreExtraElements(true);
    });
    

10、支持额外字段

在驱动库进行反序列化时,会将核对文档的字段与类型的属性,如果文档中出现了在类型中找不到对应属性的字段,默认情况下会直接抛出异常。

如果我们希望在反序列化时,即使出现了额外的字段也要将其一起保存到我们的类型中时,可以通过两种方式来实现。

方式一:使用[BsonExtraElements]特性来指定一个属性作为额外字段的载体。

  • 注意,这个属性必须是BsonDocument类型。

  • 示例

    public class Person
    {
        public string Name { get; set;
        public int Age { get; set; }
        public List<string> Hobbies {get; set;}
        [BsonExtraElements]
        public BsonDocument ExtraElements {get; set;}
    }
    

方式二:注册类型映射器

  • 示例

    BsonClassMap.RegisterClassMap<Person>(classMap =>
    {
        classMap.AutoMap();//这里表示其他属性按照默认的自动序列化
        classMap.MapExtraElementsMember(p => p.ExtraElements);
    });
    

11、带参构造函数

默认情况下,驱动库只有在类具有不带参数的构造函数时才能自动映射类。如果希望驱动库在反序列化时使用带参构造函数,可以通过两种方式来实现。

方式一:对指定的构造函数使用[BsonConstructor]特性。

  • 注意,如果同时对多个构造函数使用了此特性,那么驱动库会使用参数最多的构造函数。

  • 示例

    public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public List<string> Hobbies {get; set;}
        [BsonConstructor]
        public Person(string name, string age)
        {
            Name = name;
            Age = age;
        }
    }
    

方式二:注册类型映射器

  • 示例

    BsonClassMap.RegisterClassMap<Person>(classMap =>
    {
        classMap.AutoMap(); //这里表示其他属性按照默认的自动序列化
        classMap.MapCreator(p => new Person(p.Name, p.Age));
    });
    

二、动态序列化

有时候,我们需要在程序运行过程中根据我们类型的属性值去判断是不是要让驱动库对其进行序列化进行数据存储,也就是进行动态的序列化。

对于这一点,MongoDB.Driver规定了当我们的实体类中出现了返回bool结果且名为ShouldSerializePropertyName的方法时,驱动库在进行序列化时会根据这个方法返回的结果来决定是否对对应的属性进行序列化。

  • 强调一下方法名称是 ShouldSerialize + PropertyName
public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
    public List<string> Hobbies {get; set;}

    public bool ShouldSerializeAge()
    {
       return Age != 0;
    }
}

此外,如果不想在类中使用方法的形式,那可以通过注册类型映射器的方式来实现。文章来源地址https://www.toymoban.com/news/detail-813565.html

BsonClassMap.RegisterClassMap<Employee>(classMap =>
{
    classMap.AutoMap();
    classMap.MapMember(p => c.Age).SetShouldSerializeMethod(
        obj => ((Person) obj).Age != 0
    );
});

到了这里,关于C#使用MongoDB-第二章 序列化的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • c#示例-xml序列化和xml树

    由于指针和引用类型的存在,在运行中的程序中,数据不一定是整块的。 可能东一块西一块散落在内存的各个地方。 序列,是指连续且有序的一个整体。序列化就是把数据变为连续有序整体的过程。 经过这样处理后的数据就可以方便的进行传输和储存了。 xml是一种文本数据

    2024年02月16日
    浏览(39)
  • C#对象二进制序列化优化:位域技术实现极限压缩

    目录 1. 引言 2. 优化过程 2.1. 进程对象定义与初步分析 2.2. 排除Json序列化 2.3. 使用BinaryWriter进行二进制序列化 2.4. 数据类型调整 2.5. 再次数据类型调整与位域优化 3. 优化效果与总结 在操作系统中,进程信息对于系统监控和性能分析至关重要。假设我们需要开发一个监控程序

    2024年01月22日
    浏览(46)
  • Protobuf-net:C#高效序列化工具,助力接口传输与前端解析

      概述: Protobuf-net是C#中高效的二进制序列化工具,以紧凑、跨语言支持和卓越性能著称。通过定义消息类型、序列化和反序列化实现数据传输,并可适用于Web接口。前端可使用protobuf.js库解析Protobuf格式数据。 Protobuf-net(Protocol Buffers)是一种高效的二进制序列化工具,具有

    2024年03月09日
    浏览(40)
  • 第二章 使用 SQL Search

    本主题介绍 SQL Search 工具,这是一种用于执行上下文感知文本搜索操作的工具。要使用 SQL Search ,必须为包含要搜索的文本的每个列定义 SQL 搜索索引。然后,可以使用标准 SQL 查询以及包含 InterSystems SQL 搜索语法的 WHERE 子句来搜索文本记录。查询将返回包含指定搜索项的所

    2024年01月21日
    浏览(45)
  • 使用nlohmann json库进行序列化与反序列化

    nlohmann源码仓库:https://github.com/nlohmann/json 使用方式:将其nlohmann文件夹加入,包含其头文件json.hpp即可 demo

    2024年02月10日
    浏览(40)
  • (SpringBoot)第二章:Spring创建和使用

    注意 :在Java中对象也叫做Bean,所以后续文章中用Be

    2024年02月08日
    浏览(43)
  • 第二章:在html中使用javascript

    1、在html页面中插入js的主要方法就是使用script元素 2、html4.01为script定义了以下6个属性:【language已经废弃,其他5个属性都是可选的】 async  表示应该 立即下载脚本 ,但不应该妨碍页面中的其他操作,比如下载其他资源或等待加载其他脚本, 仅对外部文件有效【指定async属

    2024年02月17日
    浏览(35)
  • drf——Request源码分析、序列化组件、序列化类的使用(字段类和参数)、反序列化校验和保存

    views.py中 urls.py中 序列化类 字段 字段构造方式 BooleanField BooleanField() NullBooleanField NullBooleanField() CharField CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True) EmailField EmailField(max_length=None, min_length=None, allow_blank=False) RegexField RegexField(regex, max_length=None, min_length=None, a

    2024年02月05日
    浏览(40)
  • Protobuf协议初级详解(python使用)从安装到序列化-反序列化

    Protobuf是一种轻便高效的结构化数据存储格式,可以用于结构化数据序列化,很适合做数据存储或 RPC 数据交换格式。它可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。 可以简单理解为,是一种跨语言、跨平台的数据传输格式。与j

    2024年02月04日
    浏览(43)
  • 【spark】序列化和反序列化,transient关键字的使用

    Spark是基于JVM运行的进行,其序列化必然遵守Java的序列化规则。 序列化就是指将一个对象转化为二进制的byte流(注意,不是bit流),然后以文件的方式进行保存或通过网络传输,等待被反序列化读取出来。序列化常被用于数据存取和通信过程中 spark dirver和executor间传递变量

    2024年02月10日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包