多形オブジェクト
項目一覧
Overview
多形オブジェクトは、1 つ以上の親クラスからプロパティとメソッドを継承します。 これらのオブジェクトは、.NET/C# ドライバーが BSON ドキュメントとの間で正しく直列化するように特別なマッピングを必要とします。
このガイドでは、次の点について説明しています。
多形型を逆直列化する方法
.NET/C# ドライバーに含まれる弁別子の規則
カスタム弁別子規則の作成方法
このページの例では、次の継承階層を使用します。
public class Animal { } public class Cat : Animal { } public class Dog : Animal { } public class Lion : Cat { } public class Tiger : Cat { }
多形オブジェクトの逆直列化
シリアライザーが多形オブジェクトを逆直列化する前に、継承階層内のすべてのクラスの関係をドキュメントする必要があります。
オートマッパーを使用してクラスをマッピングする場合は、階層内の各基本クラスに [BsonKnownTypes]
属性を適用します。 基本クラスから直接継承する各クラスを引数として渡します。
次の例えは、 Animal
階層のクラスに[BsonKnownTypes]
属性を適用する方法を示しています。
[ ]public class Animal { } [ ]public class Cat : Animal { } public class Dog : Animal { } public class Lion : Cat { } public class Tiger : Cat { }
注意
BsonKownTypes の使用
[BsonKnownTypes]
属性は親クラスにのみ適用します。 階層内のすべての子クラスではなく、クラスから直接継承する型のみを引数として渡します。
クラス マップを手動で作成している場合は、次の例に示すように、階層内のすべてのクラスに対してBsonClassMap.RegisterClassMap<T>()
メソッドを呼び出します。
BsonClassMap.RegisterClassMap<Animal>(); BsonClassMap.RegisterClassMap<Cat>(); BsonClassMap.RegisterClassMap<Dog>(); BsonClassMap.RegisterClassMap<Lion>(); BsonClassMap.RegisterClassMap<Tiger>();
弁別子を使用する
MongoDB では、弁別子とは、ドキュメントが逆直列化するクラスを識別するためにドキュメントに追加されるフィールドです。 コレクションに 1 つの継承階層から複数の型が含まれている場合、弁別子は各ドキュメントが正しいクラスに逆シリアル化されることを確認します。 .NET/C# ドライバーは、BSON ドキュメントの_t
という名前のフィールドに弁別子の値を保存します。 一般的に、 _t
は BSON ドキュメント内の_id
に続く 2 番目のフィールドです。
弁別子規則は、弁別子フィールドに保存される値を定義します。 このセクションでは、.NET/C# ドライバーに含まれる弁別子規則と、カスタム弁別子規則を作成する方法について学習できます。
ScalaDiscriminatorConvention
デフォルトでは、.NET/C# ドライバーはScalarDiscriminatorConvention
を使用します。 この規則に従って、.NET/C# ドライバーは_t
フィールドの値を、ドキュメントが直列化されたクラスの名前に設定します。
サンプルのAnimal
クラスとその各サブクラスのインスタンスを作成するとします。 これらのオブジェクトを単一のコレクションに直列化すると、.NET/C# ドライバーはScalarDiscriminatorConvention
を適用し、対応する BSON ドキュメントは次のように表示されます。
{ _id: ..., _t: "Animal", ... } { _id: ..., _t: "Cat", ... } { _id: ..., _t: "Dog", ... } { _id: ..., _t: "Lion", ... } { _id: ..., _t: "Tiger", ... }
ScalarDiscriminatorConvention
は簡潔な弁別子の値を使用しますが、クエリを実行するのが困難になる場合があります。 たとえば、 タイプまたはサブタイプCat
のすべてのドキュメントを検索するには、検索する各クラスを明示的にリストする必要があります。
var query = coll.Aggregate().Match(a => a is Cat || a is Lion || a is Tiger);
HierarchicalDiscriminatorConvention
多形型のコレクションに対するクエリを簡素化するには、 HierarchicalDiscriminatorConvention
を使用できます。 この規則によると、 _t
の値は、ドキュメントの型の継承階層にあるすべてのクラスの配列です。
HierarchicalDiscriminatorConvention
を使用するには、継承階層の基本クラスにルート クラスとしてラベルを付けます。 オートマッパーを使用している場合は、クラスに[BsonDiscriminatorAttribute]
属性を適用し、 RootClass = true
を引数として渡して、ルート クラスにラベルを付けます。 次のコード例では、 Animal
クラスを例の継承階層のルートとしてラベル付けします。
[ ][ ]public class Animal { }
クラス マップを手動で作成している場合は、ルート クラスのクラス マップを登録するときに、 SetIsRootClass()
メソッドを呼び出し、 true
を引数として渡します。 次のコード例では、5 つのサンプル クラスすべてのクラス マップを登録しますが、継承階層のルートとしてラベル付けするのはAnimal
クラスのみです。
BsonClassMap.RegisterClassMap<Animal>(classMap => { classMap.AutoMap(); classMap.SetIsRootClass(true); }); BsonClassMap.RegisterClassMap<Cat>(); BsonClassMap.RegisterClassMap<Dog>(); BsonClassMap.RegisterClassMap<Lion>(); BsonClassMap.RegisterClassMap<Tiger>();
たとえば、例のAnimal
クラスを継承階層のルートとしてラベル付けし、 Animal
クラスとその各サブクラスのインスタンスを作成します。 これらのオブジェクトを単一のコレクションに直列化すると、.NET/C# ドライバーはHierarchicalDiscriminatorConvention
を適用し、対応する BSON ドキュメントは次のように表示されます。
{ _id: ..., _t: "Animal", ... } { _id: ..., _t: ["Animal", "Cat"], ... } { _id: ..., _t: ["Animal", "Dog"], ... } { _id: ..., _t: ["Animal", "Cat", "Lion"], ... } { _id: ..., _t: ["Animal", "Cat", "Tiger"], ... }
重要
ルート クラス弁別子
ルート クラスにマップされたドキュメントでは、弁別子フィールドに string 値が引き続き使用されます。
HierarchicalDiscriminatorConvention
を使用すると、次の例に示すように、単一のブール値条件を使用して、 Cat
タイプまたはサブタイプ のすべてのドキュメントを検索できます。
var query = coll.Aggregate().Match(a => a is Cat);
カスタム弁別子規則
.NET/C# ドライバーの規則に準拠していないデータ(たとえば、別のドライバーやオブジェクト マッパーによって MongoDB に挿入されたデータ)を処理する場合は、弁別子に別の値を使用する必要がある場合があります。フィールドを使用して、クラスがこれらの規則に一致していることを確認します。
オートマッパーを使用している場合は、クラスに [BsonDiscriminator]
属性を適用し、カスタム弁別子の値をstring引数として渡すことで、クラスの弁別子フィールドにカスタム値を指定できます。 次のコード例では、 Animal
クラスの弁別子フィールドの値を "myAnyalClass" に設定します。
[ ]public class Animal { }
クラス マップを手動で作成している場合は、クラス マップを登録するときにSetDiscriminator()
メソッドを呼び出し、カスタム弁別子の値を引数として渡します。 次のコード例では、 Animal
クラスの弁別子フィールドの値を "myAnyalClass" に設定します。
BsonClassMap.RegisterClassMap<Animal>(classMap => { classMap.AutoMap(); classMap.SetDiscriminator("myAnimalClass"); });
前のAnimal
クラスのインスタンスは、直列化後に次のように表示されます。
{ "_id": "...", "_t": "myAnimalClass"}