Docs Menu
Docs Home
/ / /
C#/.NET
/ /

POCO

項目一覧

  • Overview
  • POCO を作成
  • カスタム直列化
  • 読み取り専用プロパティを直列化
  • フィールド名を設定
  • 型表現を選択する
  • フィールドの順序を設定
  • Id プロパティを特定
  • 空のフィールドを省略
  • デフォルト値をカスタマイズ
  • ID ジェネレータを指定
  • DateTime 直列化をカスタマイズ
  • 辞書の直列化をカスタマイズ
  • 詳細情報
  • API ドキュメント

このガイドでは、操作とクエリに "Plain Old CLR/Class Objects" (POCO) を .NET/C# ドライバーと共に使用する方法について学ぶことができます。POCO は、フレームワーク固有の基本クラスやインターフェースから機能を継承しない単純なクラス オブジェクトです。慣用的なドライバーの使用法に準拠し、最高のパフォーマンスを実現するために、C# コードで 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] 属性をプロパティに適用します。

次のコード例では、Clothing クラスの Upc プロパティに [BsonElement] 属性を適用します。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; }
[BsonElement]
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; }
[BsonElement("year_built")]
public int YearBuilt { get; set; }
}

C# クラスを定義するときはパスカルケースの命名規則を使用するのが一般的ですが、[BsonElement()] 属性を使用すると、MongoDB コレクションで別の命名規則またはカスタム命名規則を選択できます。

Tip

カスタムフィールド名の規則を設定する

すべてのプロパティをカスタムフィールド名で直列化する場合は、[BsonElement()] 属性を使用する代わりに ConventionPack を定義できます。たとえば、パスカルケースの命名規則を使用してクラスを定義する場合、次のコードを使用して直列化されたドキュメントでキャメルケースのフィールド名を使用できます。

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; }
[BsonRepresentation(BsonType.Int32)]
public char YearBuilt { get; set; }
}

有効な型変換の詳細については、「C# 変換の仕様」を参照してください。

ドライバーは、POCO で指定された順序でプロパティを BSON フィールドに直列化します。既存のスキーマと一致するようにプロパティをカスタム順序で保存するには、[BsonElement()] 属性に Order という名前のパラメーターを指定できます。次のコード例では、ドライバーは Style プロパティの後に YearBuilt プロパティを保存します。

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

明示的に Order が指定されていないプロパティの場合、ドライバーは Order が明示的に指定されているプロパティの後に、デフォルトの順序でそれらを直列化します。

デフォルトでは、ドライバーは Idid、または _id という名前のパブリック プロパティを BSONの _id フィールドにマッピングします。_id フィールドにマッピングするプロパティを明示的に選択するには、[BsonId()] 属性を使用します。次のコード例は、Identifier プロパティを _id フィールドにマッピングします。

public class House
{
[BsonId]
public string Identifier { get; set; }
}

警告

複数の ID フィールド

[BsonId()] 属性を使用して複数のプロパティを _id フィールドとして指定すると、ドライバーは DuplicateBsonMemberMapAttributeException をスローします。同じデータベースのフィールドを複数回指定した場合(たとえば、POCO に Id_id という名前のプロパティが含まれている場合)、ドライバーは BsonSerializationException をスローします。

デフォルトでは、ドライバーは未定義のプロパティを null 値を持つフィールドとして直列化します。直列化の際に未定義のプロパティを無視するには、[BsonIgnore] 属性を使用します。次のコードは、YearBuilt プロパティが未定義の場合にドライバーが直列化しないようにする方法を示しています。

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

C# では、プロパティには値を割り当てるまでデフォルト値が設定されます。デフォルト値は、プロパティのデータ型によって異なります。たとえば、参照型プロパティのデフォルト値は null です。

プロパティに別のデフォルト値を指定するには、プロパティに [BsonDefaultValue()] 属性を適用し、任意のデフォルト値を引数として渡します。

次のコード例では、[BsonDefaultValue()] 属性を YearBuilt プロパティに適用します。このプロパティに値が割り当てられるまで、その値は 1900 です。

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);
});

デフォルトでは、.NET/C# ドライバーは、デフォルト値を持つプロパティを含む、すべてのプロパティを直列化します。デフォルト値を持つプロパティを無視するようにドライバーに指定するには、[BsonIgnoreIfDefault] 属性を使用します。

次のコード例では、[BsonIgnoreIfDefault] 属性を YearBuilt プロパティに適用します。このプロパティの値がそのデータ型のデフォルト(int プロパティの場合は 0)の場合、ドライバーはそれを直列化しません。

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);
});

このデフォルト値が含まれている場合は、プロパティに別のデフォルト値を指定することも、そのプロパティを無視するようにドライバーに指示することもできます。これを行うには、次のコード例に示すように、プロパティに [BsonDefaultValue()] 属性と [BsonIgnoreIfDefault] 属性の両方を適用します。

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

前のコード例では、次の直列化動作を設定しています。

  • YearBuilt プロパティに値が割り当てられていない場合は、指定されたデフォルト値 1900 が設定されます。

  • このプロパティのデフォルト値は 1900 であるため、プロパティがこの値を持つ場合、ドライバーはプロパティを無視します。

MongoDB コレクション内のすべてのドキュメントにはユニークな ID が必要です。オブジェクトをコレクションに直列化する際、Id プロパティがそのデータ型のデフォルト値を持つ場合、.NET/C# ドライバーはそれを直列化しません。代わりに、ドライバーはプロパティのユニークな ID 値を生成します。

Id プロパティの型が GuidObjectId、または 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
{
[BsonId(IdGenerator = typeof(CombGuidGenerator))]
public Guid Id { get; set; }
}

注意

前のコード例では、Id プロパティに [BsonId(IdGenerator)] 属性がない場合、ドライバーは Id フィールドに割り当てる非 COMB GUID を生成します。

次の例に示すように、クラスマップを登録する際に IIdGenerator 型を指定することもできます。

BsonClassMap.RegisterClassMap<House>(classMap =>
{
classMap.AutoMap();
classMap.MapIdMember(h => h.Id).SetIdGenerator(CombGuidGenerator.Instance);
});

Tip

複数のクラスに対して IIdGenerator を指定する

RegisterIdGenerator() メソッドを使用して、特定のデータ型のすべての Id プロパティに対して 1 つの IIdGenerator を指定できます。次のコード例では、すべての Guid ID に対して CombGuidGenerator 型を使用するようにドライバーに指示します。

BsonSerializer.RegisterIdGenerator(
typeof(Guid),
CombGuidGenerator.Instance
);

.NET/C# ドライバーには、Id プロパティを検証し、ID が無効な場合に例外をスローする IIdGenerator 型も含まれています。次の表に、これらの型を示します。

ID の検証
IIdGenerator タイプ
NULLではない
NullIdChecker
すべてがゼロではない
ZeroIdChecker<T>

次のコード例では、House クラスの Id プロパティにデフォルト値(null)が含まれている場合、ドライバーは例外をスローします。

public class House
{
[BsonId(IdGenerator = typeof(NullIdChecker))]
public Guid Id { get; set; }
}

.NET/C# ドライバーが DateTime プロパティを直列化する方法をカスタマイズするには、[BsonDateTimeOptions()] 属性を使用し、任意の設定を引数として指定します。

DateTime プロパティが日付のみを表す場合は、[BsonDateTimeOptions(DateOnly = true)] 属性を適用できます。これを実施すると、ドライバーは値に対してタイムゾーンの変換を行いません。

次のコード例では、PatientRecord クラスは DateOfBirth プロパティに DateTime を使用します。[BsonDateTimeOptions(DateOnly = true)] 属性は、プロパティに日付のみが含まれていることを示します。

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

[BsonDateTimeOptions()] 属性を使用して、DateTime プロパティの DateTimeKind を指定することもできます。次のコード例では、PatientRecord クラスに DateTime 型の AppointmentTime プロパティがあります。[BsonDateTimeOptions(Kind = DateTimeKind.Local)] 属性は、プロパティの値の時間コンポーネントがローカル時間であることを示します。ドライバーがこのプロパティを直列化する際、時刻を UTC に変換します。これは MongoDB に保存される時刻の標準形式です。

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

クラスマップを登録するときに、前述の DateTime オプションの 1 つまたは両方を指定することもできます。

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));
});

Tip

DateTimeKind Values

DateTimeKind列挙型は .NET フレームワークの一部です。 そのメンバーの詳細について は、 DateTimeMany 列挙型に関する Microsoft のドキュメントを参照してください。

DictionaryRepresentation 列挙型は、.NET/C# ドライバーが Dictionary インスタンスを直列化できる形式を定義します。この列挙型には、次のノードが含まれます。

  • Document:(デフォルト)ドライバーは DictionaryBsonDocument に直列化します。辞書内の各エントリは、名前がエントリのキーと等しく、値がエントリの値と等しい値を持つ BsonElement です。この表現を使用できるのは、辞書内のすべてのキーが有効な BsonElement 名でもある文字列の場合のみです。

  • ArrayOfArrays: ドライバーは辞書を BsonArray に直列化します。辞書内の各エントリは、エントリのキーとエントリの値を含む、ネストされた 2 要素の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; }
[BsonDictionaryOptions(DictionaryRepresentation.ArrayOfDocuments)]
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 フィールドを BSON Double 型として直列化することを指定します。

  • [BsonDefaultValue()]は、値が割り当てられていない場合に、Name プロパティを "Generic item" に設定します。

  • [BsonDateTimeOptions(DateOnly = true)]は、 DateTimeプロパティが日付値のみを表し、時刻は関連付けられていないことを指定します。

public class Clothing
{
public ObjectId Id { get; set; }
[BsonElement("name")]
[BsonDefaultValue("Generic item")]
public string Name { get; set; }
[BsonElement("inStock")]
public bool InStock { get; set; }
[BsonElement("price")]
[BsonRepresentation(BsonType.Decimal128)]
public decimal Price { get; set; }
[BsonElement("colorSelection")]
public List<string> ColorSelection { get; set; }
[BsonElement("listedDate")]
[BsonDateTimeOptions(DateOnly = true)]
public DateTime ListedDate { get; set; }
[BsonElement("sizeGuide")]
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 ドキュメント を参照してください。

POCO を使用した追加の読み取りおよび書き込み操作の例については、 使用例または「CRUD の基礎」ページを参照してください。

ドライバーが BSON ドキュメントを POCO にマッピングする方法の詳細については、「クラスマッピング」を参照してください。

このガイドで説明したメソッドや型の詳細については、次の API ドキュメントを参照してください。

戻る

クラスマッピング