Menu Docs
Página inicial do Docs
/ / /
C#/.NET
/ /

Objetos polimórficos

Nesta página

  • Visão geral
  • Desserialização de objetos polimórficos
  • Use discriminadores
  • ScalarDiscriminatorConvention
  • HierarchicalDiscriminatorConvention
  • Convenções de discriminadores personalizados

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
{
}

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:

[BsonKnownTypes(typeof(Cat), typeof(Dog))]
public class Animal
{
}
[BsonKnownTypes(typeof(Lion), typeof(Tiger))]
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 .

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.

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

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:

[BsonDiscriminator(RootClass = true)]
[BsonKnownTypes(typeof(Cat), typeof(Dog)]
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);

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":

[BsonDiscriminator("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"}

Voltar

POCOs