Overview
在本指南中,您可以了解如何使用“Plain Old CLR/Class Objects”,或 POCO,以及 .NET/C# 驱动程序进行操作和查询。POCO 是简单的类对象,不继承任何特定于框架的基本类或接口的功能。我们建议在 C# 代码中使用 POCO,以遵循一致的驱动程序用法并实现最佳性能。
如果您想学习;了解有关如何将 POCO 与.NET/ C#驱动程序结合使用的更多信息,或者如果您必须调整驱动程序的默认字段映射行为,请阅读本指南。
创建 POCO
您可以通过定义不通过框架实现接口或扩展类的简单类来创建 POCO。当您使用 POCO 执行读取或写入等操作时,驱动程序会在内部将 POCO 序列化 或转换为 BSON。
选择 POCO 或 BSON 标签页以查看驱动程序如何将示例 POCO 序列化为 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; } }
{ "_id": ObjectId("..."), "Name": "Long Sleeve Shirt", "InStock": true, "Price": 17.99, "ColorSelection": [ "black", "navy", "red" ] }
您可以使用适合您需求的任何对象结构来定义 POCO,包括嵌套对象、数组、列表和任何数据类型。
自定义序列化
如果默认的字段映射行为不能满足您的需求,您可以使用与序列化相关的属性来指定自定义行为。这些属性会更改驾驶员序列化 POCO 每个属性的方式。本节介绍一些常见的与序列化相关的属性。
序列化只读属性
如果属性为只读,则自动映射器不会将其包含在类映射中以进行序列化。要强制自动映射器将属性包含在类映射中,则将 [BsonElement] 属性应用于该属性。
以下代码示例将 [BsonElement] 属性应用于 Clothing 类的 Upc 属性。Upc 为只读属性,因为它拥有 get 方法,但没有 set 方法。
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; } [] public int Upc { get; } }
您还可以在注册类映射时添加只读属性,如以下示例所示:
BsonClassMap.RegisterClassMap<Clothing>(classMap => { classMap.AutoMap(); classMap.MapProperty(c => c.Upc); });
注意
当 .NET/C# 驱动程序序列化只读属性时,该属性及其值将存储在数据库中,但不会再次反序列化。
设置字段名称
驱动程序将 POCO 属性序列化为具有相同字段名称和大小写的 BSON 字段。要以不同名称存储属性,则使用 [BsonElement()] 属性。以下代码将 House 类的 YearBuilt 属性映射到序列化 BSON 文档中的 year_built 字段:
public class House { public Guid Id { get; set; } [] public int YearBuilt { get; set; } }
尽管在定义 C# 类时通常使用 Pascal case 命名规范,但使用 [BsonElement()] 属性允许您在 MongoDB 集合中选择不同的或自定义命名规范。
提示
设置自定义字段名称规范
若要使用自定义字段名称序列化每个属性,您可以定义 ConventionPack 而不是使用 [BsonElement()] 属性。例如,如果您使用 Pascal case 命名规范定义类,则可以使用以下代码在序列化文档中使用大小写字段名称:
var camelCaseConvention = new ConventionPack { new CamelCaseElementNameConvention() }; ConventionRegistry.Register("CamelCase", camelCaseConvention, type => true);
有关规定的更多信息,请参阅序列化指南的 规则部分。
选择类型表示
要将 C# 属性序列化为特定 BSON 类型,则使用 [BsonRepresentation()] 属性。仅当 C# 基元类型可转换为您指定的 BSON 类型时,此方法才有效。
在以下代码示例中,驱动程序将 YearBuilt 属性(在 C# 中定义为 char)序列化为 BSON Int32 类型:
public class House { public Guid Id { get; set; } [] public char YearBuilt { get; set; } }
有关有效类型转换的更多信息,请参阅 C# 转换规范。
重要
序列化 NaN 和 Infinity
如果尝试将浮点 Infinity 或 NaN 值序列化或反序列化为整数表示形式,驱动程序会抛出 OverflowException。
设置字段顺序
驱动程序按照 POCO 中指定的顺序将属性序列化为 BSON 字段。要按照自定义顺序存储属性以匹配现有模式,可以在 [BsonElement()] 属性中指定 Order 命名参数。在以下代码示例中,驱动程序将 YearBuilt 属性存储在 Style 属性之后:
public class House { public Guid Id { get; set; } [] public int YearBuilt { get; set; } [] public string Style { get; set; } }
如果任何属性没有显式 Order,则驱动程序将在具有显式顺序的属性之后按默认顺序对其进行序列化。
识别 Id 属性
默认情况下,驱动程序会将名为 Id、id 或 _id 的任何公共属性映射到 BSON _id 字段。要明确选择映射到 _id 字段的属性,则使用 [BsonId()] 属性。以下代码示例将 Identifier 属性映射到 _id 字段:
public class House { [] public string Identifier { get; set; } }
警告
多个 ID 字段
如果使用 [BsonId()] 属性将多个属性标识为 _id 字段,则驱动程序会抛出 DuplicateBsonMemberMapAttributeException。如果多次指定同一数据库字段(例如,如果 POCO 包含名为 Id 和 _id 的属性),则驱动程序会抛出 BsonSerializationException。
注意
嵌套文档 ID
本节中描述的 _id字段映射逻辑仅适用于根文档,应用用于嵌套文档。
指定 ID 生成器
MongoDB 数据集中的每个文档都必须有一个唯一的 ID。将对象序列化为集合时,如果其 ID 属性包含其数据类型的默认值(通常为 null),则 .NET/C# 驱动程序不会序列化该默认值。相反,此驱动程序会尝试生成唯一的 ID 值并将其分配给该属性。
要启用属性的 ID 生成,您必须指定驱动程序用于该属性的 ID 生成器。您可以通过将 [BsonId] 属性应用于该属性并传递 IdGenerator 参数来指定生成器类型。下表介绍了 .NET/C# 驱动程序中可用的 ID 生成器:
Id 字段数据类型 | 如何使用 | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| 要使用 COMB 算法生成唯一的 要在没有 COMB 算法的情况下生成唯一的 如要了解更多信息,请参阅 GUIDs 指南。 | ||||||||||
| 对于数据类型为 | ||||||||||
| 如果您指定将数据类型为 要为未序列化为 | ||||||||||
| 将 |
或者,您还可以在注册类映射时指定 IIdGenerator 类型,如以下示例所示:
BsonClassMap.RegisterClassMap<House>(classMap => { classMap.AutoMap(); classMap.MapIdMember(h => h.Id).SetIdGenerator(CombGuidGenerator.Instance); });
提示
为多个类指定 IIdGenerator
您可以使用 RegisterIdGenerator() 方法为某一数据类型的所有 Id 属性指定一个 IIdGenerator。以下代码示例指示驱动程序对所有 Guid ID 使用 CombGuidGenerator 类型:
BsonSerializer.RegisterIdGenerator( typeof(Guid), CombGuidGenerator.Instance );
.NET/C# 驱动程序还包括 IIdGenerator 类型,用于验证 Id 属性并在 ID 无效时抛出异常。下表列出这些类型:
ID 验证 | IIdGenerator 类型 |
|---|---|
不为空 |
|
并非全部为零 |
|
在以下代码示例中,如果 House 类的 Id 属性包含默认值 (null),则驱动程序会抛出异常:
public class House { [] public Guid Id { get; set; } }
省略字段
要防止驱动程序序列化指定字段,请使用 [BsonIgnore] 属性。以下代码展示了如何防止驱动程序序列化 YearBuilt 属性:
public class House { public Guid Id { get; set; } [] public int YearBuilt { get; set; } public string Style { get; set; } }
即使您定义了 YearBuilt 属性,该字段也不会保存在 MongoDB 中。
注意
您可以定义类映射以防止特定字段被序列化。如要了解更多信息和查看示例,请参见类映射指南的省略字段部分。
省略空字段
默认情况下,驱动程序会序列化具有 null 值的未初始化属性。如要在序列化过程中忽略空属性,请使用 [BsonIgnoreIfNull] 属性。以下代码展示了如何在 Style 属性未初始化时阻止驱动程序序列化该属性:
public class House { public Guid Id { get; set; } [] public string Style { get; set; } public int YearBuilt { get; set; } }
您还可以指示驱动程序在注册类映射时忽略包含 null 值的属性,如以下示例所示:
BsonClassMap.RegisterClassMap<House>(classMap => { classMap.AutoMap(); classMap.MapMember(h => h.Style).SetIgnoreIfNull(true); });
注意
值类型属性
您不能使用 [BsonIgnoreIfNull] 属性或 SetIgnoreIfNull() 方法来防止未初始化的值类型属性被序列化,除非将这些属性标记为可为 null。不过,您可以使用 [BsonIgnoreIfDefault] 属性或 SetIgnoreIfDefault()类映射方法,这些方法在本指南的自定义默认值部分中有相关介绍。
自定义默认值
在 C# 中,属性在赋值之前均为默认值。默认值取决于属性的数据类型。例如,引用类型属性的默认值为 null。
要为属性指定不同的默认值,则将 [BsonDefaultValue()] 属性应用于该属性并将所需默认值作为参数传递。
以下代码示例将 [BsonDefaultValue()] 属性应用于 YearBuilt 属性。在为该属性分配值之前,其值为 1900。
public class House { public Guid Id { get; set; } [] public int YearBuilt { get; set; } }
还可以在注册类映射时为属性指定不同的默认值,如以下示例所示:
BsonClassMap.RegisterClassMap<House>(classMap => { classMap.AutoMap(); classMap.MapMember(h => h.YearBuilt).SetDefaultValue(1900); });
默认情况下,.NET/C# 驱动程序会序列化所有属性,包括那些包含默认值的属性。若要指示驱动程序忽略具有默认值的属性,则使用 [BsonIgnoreIfDefault] 属性。
以下代码示例将 [BsonIgnoreIfDefault] 属性应用于 YearBuilt 属性。如果此属性的值是其数据类型的默认值(int 属性为 0),则驱动程序将不会对其序列化。
public class House { public Guid Id { get; set; } [] public int YearBuilt { get; set; } }
您还可以指示驱动程序在注册类映射时忽略包含默认值的属性,如以下示例所示:
BsonClassMap.RegisterClassMap<House>(classMap => { classMap.AutoMap(); classMap.MapMember(h => h.YearBuilt).SetIgnoreIfDefault(true); });
您可以为属性指定不同的默认值,并指示驱动程序忽略该属性(如果该属性包含此默认值)。为此,将 [BsonDefaultValue()] 和 [BsonIgnoreIfDefault] 属性应用于该属性,如以下代码示例所示:
public class House { public Guid Id { get; set; } [] [] public int YearBuilt { get; set; } }
前面的代码示例设置了以下序列化行为:
如果没有为
YearBuilt属性赋值,则其指定默认值为1900。由于
1900是此属性的默认值,因此如果该属性具有此值,则驱动程序将忽略该属性。
自定义 DateTime 序列化
要自定义 .NET/C# 驱动程序序列化 DateTime 属性的方式,则使用 [BsonDateTimeOptions()] 属性并将所需设置指定为参数。
如果 DateTime 属性仅表示日期,您可以对其应用 [BsonDateTimeOptions(DateOnly = true)] 属性。如果这样做,驱动程序将不会对该值执行任何时区转换。
在以下代码示例中,PatientRecord 类为 DateOfBirth 属性使用 DateTime。[BsonDateTimeOptions(DateOnly = true)] 属性指示该属性仅包含日期。
public class PatientRecord { public Guid Id { get; set; } [] public DateTime DateOfBirth { get; set; } }
您也可以使用 [BsonDateTimeOptions()] 属性指定 DateTime 属性的 DateTimeKind。在以下代码示例中,PatientRecord 类有一个 AppointmentTime 属性,其类型为 DateTime。[BsonDateTimeOptions(Kind = DateTimeKind.Local)] 属性指示属性值的时间部分为当地时间。当驱动程序序列化此属性时,它会将时间转换为 UTC,这是 MongoDB 中存储的时间的标准格式。
public class PatientRecord { public Guid Id { get; set; } [] public DateTime AppointmentTime { get; set; } }
您还可以在注册类映射时指定前面的一个或两个 DateTime 选项:
BsonClassMap.RegisterClassMap<House>(classMap => { classMap.AutoMap(); classMap.MapMember(p => p.DateOfBirth) .SetSerializer(new DateTimeSerializer(dateOnly: true)); classMap.MapMember(p => p.AppointmentTime) .SetSerializer(new DateTimeSerializer(DateTimeKind.Local)); });
自定义 DateOnly 序列化
如要自定义 .NET/C# 驱动程序如何序列化 DateOnly 属性,请使用 [BsonDateOnlyOptions()] 属性并指定以下设置:
Representation:设置为BsonType实例,指定DateOnly值在 MongoDB 中的存储方式。DocumentFormat:此选项仅在您将Representation属性设置为BsonType.Document时适用,否则将被忽略。您可以将DocumentFormat设置为以下DateOnlyDocumentFormat任意一个枚举值:DateTimeTicks(默认):文档包含DateTime(BsonType.DateTime)和Ticks(BsonType.Int64)字段YearMonthDay:文档包含Year、Month和Day字段,这些字段具有BsonType.Int32值
在以下代码示例中,PatientRecord 类包含一个具有 DateOnly 值的 DateOfBirth 属性。该属性指示驱动程序将值存储为嵌套文档,其中包含给定年份、月份和日期的字段。
public class PatientRecord { public Guid Id { get; set; } [] public DateOnly DateOfBirth { get; set; } }
提示
使用 DateOnlySerializer 设置全局行为
您可以注册一个 DateOnlySerializer 对象以全局应用序列化行为,而不是在属性级别使用 [BsonDateOnlyOptions()] 属性:
BsonSerializer.RegisterSerializer( new DateOnlySerializer(BsonType.Document, DateOnlyDocumentFormat.YearMonthDay) );
自定义字典序列化
DictionaryRepresentation 枚举定义 .NET/C# 驱动程序可用于将 Dictionary 实例进行序列化的格式。该枚举包括以下节点:
文档:(默认)驱动程序将
Dictionary序列化为BsonDocument。字典中的每个条目都是一个BsonElement,其名称等于条目的键,值等于条目的值。仅当字典中的所有键也是有效BsonElement名称的字符串时,您才能使用此表示。ArrayOfArrays:驱动程序将字典序列化为
BsonArray。字典中的每个条目都是一个嵌套的二元素BsonArray,其中包含条目的键和条目的值。ArrayOfDocuments:驱动程序将字典序列化为
BsonArray。字典中的每个条目都是{ k : key, v : value }形式的嵌套BsonDocument。由于键和值都用元素名称标记,因此您能够比ArrayOfArrays更直观地查询此格式。
在以下代码示例中,RoomSizes 属性是字典,其中包含房屋中的每个房间及其相应的大小。[BsonDictionaryOptions()] 属性指示 .NET/C# 驱动程序将此属性序列化为 BsonArray 对象,并将字典中的每个条目序列化为 { k : "<room>", v : <size> } 形式的 BsonDocument。
public class House { public Guid Id { get; set; } [] public Dictionary<string, float> RoomSizes { get; set; } }
您还可以在注册类映射时指定字典的序列化格式,如以下示例所示:
BsonClassMap.RegisterClassMap<House>(classMap => { classMap.AutoMap(); classMAp.MapMember(h => h.RoomSizes) .SetSerializer(new DictionaryInterfaceImplementerSerializer<Dictionary<string, float>> (DictionaryRepresentation.ArrayOfDocuments)); });
例子
以下示例显示如何将具有自定义字段映射规范的 Clothing 文档插入到 MongoDB 中。
以下代码定义了具有这些序列化相关属性的 Clothing 类:
[BsonElement()],用于指定大小写命名规范中的自定义字段名称[BsonRepresentation()],将Price字段序列化为 BSONDouble类型[BsonDefaultValue()],如果尚未为Name属性分配任何值,则将其设置为"Generic item"[BsonDateTimeOptions(DateOnly = true)],指定DateTime属性仅代表一个日期值,而没有关联的时间
public class Clothing { public ObjectId Id { get; set; } [] [] public string Name { get; set; } [] public bool InStock { get; set; } [] [] public decimal Price { get; set; } [] public List<string> ColorSelection { get; set; } [] [] public DateTime ListedDate { get; set; } [] public Dictionary<string, string> SizeGuide { get; set; } }
以下代码实例化 Clothing 对象并将文档插入到集合中:
var doc = new Clothing { Name = "Denim Jacket", InStock = false, Price = 32.99m, ColorSelection = new List<string> { "dark wash", "light wash" }, ListedDate = DateTime.Parse("Jan 1, 2007"), SizeGuide = new Dictionary<string, string>() { {"Small", "Chest: 38\", Waist: 38\", Shoulders: 15\""}, {"Medium", "Chest: 40\", Waist: 40\", Shoulders: 15.5\""}, {"Large", "Chest: 42\", Waist: 40\", Shoulders: 16\""} } }; _myColl.InsertOne(doc);
插入文档的 BSON 表示如下所示:
{ "_id": ObjectId("..."), "name": "Denim Jacket", "inStock": false, "price": 32.99, "colorSelection": [ "dark wash", "light wash" ], "listedDate" : ISODate("2007-01-01T00:00:00Z"), "sizeGuide" : { "Small" : "Chest: 38\", Waist: 38\", Shoulders: 15\"", "Medium" : "Chest: 40\", Waist: 40\", Shoulders: 15.5\"", "Large" : "Chest: 42\", Waist: 40\", Shoulders: 16\"" } }
更多信息
有关序列化相关属性的完整列表,请参阅 Serialization.Attributes API 文档。
要了解有关驱动程序如何将 BSON 文档映射到 POCO 的更多信息,请参阅类映射。
API 文档
要进一步了解本指南所讨论的任何方法或类型,请参阅以下 API 文档: