POCO
在此页面上
Overview
在本指南中,您可以学习如何使用"Plain Old CLR/Class Objects " ,或POCO 与 .NET/C# Driver 一起进行操作和查询。 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 类型时,此方法才有效。在以下代码示例中,在 C# 中定义为 char
的 YearBuilt
属性被序列化为 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
。
省略空字段
默认情况下,驱动程序将未定义的属性序列化为具有 null
值的字段。要在序列化过程中忽略未定义属性,则使用 [BsonIgnore]
属性。以下代码展示了如何在 YearBuilt
属性未定义时阻止驱动程序序列化该属性:
public class House { public Guid Id { get; set; } [ ] public int YearBuilt { get; set; } public string Style { get; set; } }
自定义默认值
在 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
是此属性的默认值,因此如果该属性具有此值,则驱动程序将忽略该属性。
指定 ID 生成器
MongoDB 数据集中的每个文档都必须有一个唯一的 ID。将对象序列化为集合时,如果 Id
属性包含其数据类型的默认值,则 .NET/C# 驱动程序不会对其进行序列化。相反,驱动程序会为该属性生成唯一的 ID 值。
如果 Id
属性的类型为 Guid
、ObjectId
或 string
,则驱动程序可以自行生成 ID 值。如果 Id
属性是任何其他数据类型,则必须指定驱动程序用于生成值的 IIdGenerator
类型。要指定 IIdGenerator
类型,将 [BsonId(IdGenerator)]
属性应用于属性并将 IIdGenerator
类型作为参数传递。
.NET/C# 驱动程序包括以下 IIdGenerator
类型:
Id 字段数据类型 | IIdGenerator 类型 |
---|---|
Guid 由 COMB 算法生成的值 | CombGuidGenerator |
BsonObjectId | BsonObjectIdGenerator |
在以下代码示例中,如果 House
类的 Id
属性包含默认值 (null
),则驱动程序在序列化期间使用 COMB 算法生成唯一值:
public class House { [ ] public Guid Id { get; set; } }
注意
在前面的代码示例中,如果 Id
属性没有 [BsonId(IdGenerator)]
属性,则驱动程序将生成一个非 COMB GUID 以分配给 Id
字段。
您还可以在注册类映射时指定 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 类型 |
---|---|
不为空 | NullIdChecker |
并非全部为零 | ZeroIdChecker<T> |
在以下代码示例中,如果 House
类的 Id
属性包含默认值 (null
),则驱动程序会抛出异常:
public class House { [ ] public Guid Id { get; set; } }
自定义 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)); });
提示
DateTimeKind Values
DateTimeKind
枚举是 .NET Framework 的一部分。有关其节点的更多信息,请参阅 DateTimeKind 枚举的 Microsoft 文档。
自定义字典序列化
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 文档。
有关使用 POCOS 的其他读写操作示例,请参阅 使用示例或 CRUD 基础知识页面。
要了解有关驱动程序如何将 BSON 文档映射到 POCO 的更多信息,请参阅类映射。
API 文档
要进一步了解本指南所讨论的任何方法或类型,请参阅以下 API 文档: