Objetos polimórficos
Nesta página
Visão geral
Os objetos polimórficos herdam propriedades e métodos de uma ou mais classes pai. Esses objetos exigem mapeamento especial para garantir que o .NET/C# Driver os serialize corretamente de e para documentos BSON.
Este guia explica o seguinte:
Como desserializar tipos polimórficos
As convenções de discriminador incluídas no driver .NET/C#
Como criar convenções de discriminador personalizadas
Os exemplos desta página utilizam a seguinte hierarquia de herança:
public class Animal { } public class Cat : Animal { } public class Dog : Animal { } public class Lion : Cat { } public class Tiger : Cat { }
Desserialização de objetos polimórficos
Antes que o serializador possa desserializar qualquer objeto polimórfico, você deve documentar o relacionamento de todas as classe na hierarquia de herança.
Se você estiver utilizando o mapeador automático para mapear suas classes, aplique o atributo [BsonKnownTypes]
a cada classe base na hierarquia. Passe cada classe que herda diretamente da classe base como um argumento.
O exemplo a seguir mostra como aplicar o atributo [BsonKnownTypes]
a classes na hierarquia Animal
exemplo:
[ ]public class Animal { } [ ]public class Cat : Animal { } public class Dog : Animal { } public class Lion : Cat { } public class Tiger : Cat { }
Observação
Usando tipos BsonKnown
Aplique o atributo [BsonKnownTypes]
somente às classes principais. Passe como argumentos apenas os tipos que herdam diretamente da classe, e não todas as classes filhas na hierarquia.
Ao criar um mapa de classe manualmente, chame o método BsonClassMap.RegisterClassMap<T>()
para cada classe na hierarquia, como mostrado no exemplo a seguir:
BsonClassMap.RegisterClassMap<Animal>(); BsonClassMap.RegisterClassMap<Cat>(); BsonClassMap.RegisterClassMap<Dog>(); BsonClassMap.RegisterClassMap<Lion>(); BsonClassMap.RegisterClassMap<Tiger>();
Dica
Mapas de classe
Para saber mais sobre classes de mapeamento, consulte a documentação deMapeamento de Classes do .
Use discriminadores
No MongoDB, um discriminador é um campo adicionado a um documento para identificar a classe para a qual o documento é desserializado. Quando uma coleção contém mais de um tipo de uma única hierarquia de herança, os discriminadores garantem que cada documento seja desserializado para a classe correta. O driver .NET/C# armazena o valor discriminador em um campo chamado _t
no documento BSON. Geralmente, _t
é o segundo campo no documento BSON depois _id
.
As convenções do discriminador definem o valor armazenado no campo do discriminador. Nesta seção, você pode aprender sobre as convenções do discriminador incluídas no driver .NET/C# e como criar convenções de discriminador personalizadas.
ScalarDiscriminatorConvention
Por padrão, o driver .NET/C# utiliza o ScalarDiscriminatorConvention
. De acordo com essa convenção, o driver .NET/C# define o valor do campo _t
com o nome da classe da qual o documento foi serializado.
Suponha que você crie uma instância da classe Animal
do exemplo e cada uma de suas subclasses. Se você serializar esses objetos em uma única coleção, o driver .NET/C# aplicará o ScalarDiscriminatorConvention
e os documentos BSON correspondentes serão exibidos da seguinte forma:
{ _id: ..., _t: "Animal", ... } { _id: ..., _t: "Cat", ... } { _id: ..., _t: "Dog", ... } { _id: ..., _t: "Lion", ... } { _id: ..., _t: "Tiger", ... }
O ScalarDiscriminatorConvention
usa valores discriminadores concisos, mas pode ser difícil de executar uma query. Por exemplo, para localizar todos os documentos do tipo ou subtipo Cat
, você deve listar explicitamente cada classe que está procurando:
var query = coll.Aggregate().Match(a => a is Cat || a is Lion || a is Tiger);
HierarchicalDiscriminatorConvention
Para simplificar as queries em sua coleção de tipos polimórficos, você pode usar o HierarchicalDiscriminatorConvention
. De acordo com essa convenção, o valor de _t
é uma array de todas as classes na hierarquia de herança do tipo do documento.
Para usar o HierarchicalDiscriminatorConvention
, rotule a classe base da hierarquia de herança como a classe raiz. Se você estiver usando o mapeador automático, rotule a classe raiz aplicando o atributo [BsonDiscriminatorAttribute]
à classe e passando RootClass = true
como um argumento. O exemplo de código a seguir rotula a classe Animal
como a raiz da hierarquia de herança de exemplo:
[ ][ ]public class Animal { }
Ao criar um mapa de classe manualmente, chame o método SetIsRootClass()
e passe true
como argumento ao registrar o mapa de classe para a classe raiz. O exemplo de código a seguir registra mapas de classe para todas as cinco classes de exemplo, mas rotula apenas a classe Animal
como a raiz da hierarquia de herança:
BsonClassMap.RegisterClassMap<Animal>(classMap => { classMap.AutoMap(); classMap.SetIsRootClass(true); }); BsonClassMap.RegisterClassMap<Cat>(); BsonClassMap.RegisterClassMap<Dog>(); BsonClassMap.RegisterClassMap<Lion>(); BsonClassMap.RegisterClassMap<Tiger>();
Suponha que você rotule a classe de exemplo Animal
como a raiz da hierarquia de herança e, em seguida, crie uma instância da classe Animal
e cada uma de suas subclasses. Se você serializar esses objetos em uma única coleção, o driver .NET/C# aplicará o HierarchicalDiscriminatorConvention
e os documentos BSON correspondentes serão exibidos da seguinte forma:
{ _id: ..., _t: "Animal", ... } { _id: ..., _t: ["Animal", "Cat"], ... } { _id: ..., _t: ["Animal", "Dog"], ... } { _id: ..., _t: ["Animal", "Cat", "Lion"], ... } { _id: ..., _t: ["Animal", "Cat", "Tiger"], ... }
Importante
Discriminador de classe raiz
Qualquer documento mapeado para a classe raiz ainda usa um valor de string para o campo discriminador.
Ao usar o HierarchicalDiscriminatorConvention
, você pode pesquisar todos os documentos do tipo ou subtipo Cat
usando uma única condição booleana, conforme mostrado no exemplo a seguir:
var query = coll.Aggregate().Match(a => a is Cat);
Convenções de discriminadores personalizados
Se estiver trabalhando com dados que não seguem as convenções usadas pelo driver .NET/C# — por exemplo, dados inseridos no MongoDB por outro driver ou por outro mapeador de objetos —, talvez seja necessário usar um valor diferente para o campo de discriminador, assim, você irá garantir que suas classes estejam alinhadas com essas convenções.
Se você estiver usando o automapper, poderá especificar um valor personalizado para o campo discriminador de uma classe aplicando o atributo [BsonDiscriminator]
à classe e passando o valor do discriminador personalizado como um argumento de string. O exemplo de código a seguir define o valor do campo discriminador para a classe Animal
como "myAnimalClass":
[ ]public class Animal { }
Se você estiver criando um mapa de classe manualmente, chame o método SetDiscriminator()
e passe o valor personalizado do discriminador como um argumento ao registrar o mapa de classe. O exemplo de código a seguir define o valor do campo discriminador da classe Animal
como "MyAnimalClass":
BsonClassMap.RegisterClassMap<Animal>(classMap => { classMap.AutoMap(); classMap.SetDiscriminator("myAnimalClass"); });
Uma instância da classe Animal
anterior aparece da seguinte forma após a serialização:
{ "_id": "...", "_t": "myAnimalClass"}