Docs Menu
Docs Home
/ /

Objetos polimórficos

Los objetos Polimórficos heredan propiedades y métodos de una o más clases padre. Estos objetos requieren una asignación especial para garantizar que el controlador .NET/C# los serialice correctamente hacia y desde documentos BSON.

Esta guía explica lo siguiente:

  • Cómo deserializar tipos polimórficos

  • Las convenciones discriminadoras incluidas con el controlador .NET/C#

  • Cómo crear convenciones discriminadoras personalizadas

Los ejemplos de esta página utilizan la siguiente jerarquía de herencia:

public class Animal
{
}
public class Cat : Animal
{
}
public class Dog : Animal
{
}
public class Lion : Cat
{
}
public class Tiger : Cat
{
}

Antes de que el serializador pueda deserializar cualquier objeto polimórfico, debe documentar la relación de todas las clases en la jerarquía de herencia.

Si está utilizando el automapper para mapear sus clases, aplique el [BsonKnownTypes] Atributo a cada clase base de la jerarquía. Pasa cada clase que hereda directamente de la clase base como argumento.

El siguiente ejemplo muestra cómo aplicar el atributo [BsonKnownTypes] a las clases en la jerarquía de ejemplo Animal:

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

Nota

Uso de BsonKnownTypes

Aplique el [BsonKnownTypes] atributo solo a las clases padre. Pase como argumentos solo los tipos que heredan directamente de la clase, no todas las clases hijas de la jerarquía.

Si está creando un mapa de clases manualmente, llame al método BsonClassMap.RegisterClassMap<T>() para cada clase en la jerarquía, como se muestra en el siguiente ejemplo:

BsonClassMap.RegisterClassMap<Animal>();
BsonClassMap.RegisterClassMap<Cat>();
BsonClassMap.RegisterClassMap<Dog>();
BsonClassMap.RegisterClassMap<Lion>();
BsonClassMap.RegisterClassMap<Tiger>();

Tip

Mapas de clases

Para obtener más información sobre las clases de mapeo, consulte la Documentación de mapeo de clases.

En MongoDB, un discriminador es un campo que se añade a un documento para identificar la clase a la que se deserializa. Cuando una colección contiene más de un tipo de una misma jerarquía de herencia, los discriminadores garantizan que cada documento se deserialice a la clase correcta. El controlador .NET/C# almacena el valor del discriminador en un campo llamado _t en el documento BSON. Generalmente, _t es el segundo campo en el documento BSON después _id de.

Las convenciones de discriminador definen el valor almacenado en el campo discriminador. En esta sección, aprenderá sobre las convenciones de discriminador incluidas en el controlador .NET/C# y cómo crear convenciones de discriminador personalizadas.

De forma predeterminada, el controlador .NET/C# utiliza ScalarDiscriminatorConvention. Según esta convención, el controlador .NET/C# establece el valor del campo _t con el nombre de la clase desde la que se serializó el documento.

Supongamos que crea una instancia de la clase de ejemplo Animal y cada una de sus subclases. Si serializa estos objetos en una sola colección, el controlador .NET/C# aplica el ScalarDiscriminatorConvention y los documentos BSON correspondientes aparecen de la siguiente manera:

{ _id: ..., _t: "Animal", ... }
{ _id: ..., _t: "Cat", ... }
{ _id: ..., _t: "Dog", ... }
{ _id: ..., _t: "Lion", ... }
{ _id: ..., _t: "Tiger", ... }

El ScalarDiscriminatorConvention usa valores discriminadores concisos, pero puede ser difícil ejecutar una consulta sobre él. Por ejemplo, para encontrar todos los documentos del tipo o subtipo Cat, debe enumerar explícitamente cada clase que busca:

var query = coll.Aggregate().Match(a => a is Cat || a is Lion || a is Tiger);

Para simplificar las consultas en su colección de tipos polimórficos, puede usar el HierarchicalDiscriminatorConvention. De acuerdo con esta convención, el valor de _t es un arreglo de todas las clases en la jerarquía de herencia del tipo de documento.

Para usar HierarchicalDiscriminatorConvention, etiquete la clase base de su jerarquía de herencia como la clase raíz. Si usa el autoasignador, etiquete la clase raíz aplicando el atributo [BsonDiscriminatorAttribute] a la clase y pasando RootClass = true como argumento. El siguiente ejemplo de código etiqueta la clase Animal como la raíz de la jerarquía de herencia de ejemplo:

[BsonDiscriminator(RootClass = true)]
[BsonKnownTypes(typeof(Cat), typeof(Dog)]
public class Animal
{
}

Si crea un mapa de clases manualmente, llame al método SetIsRootClass() y pase true como argumento al registrar el mapa de clases para la clase raíz. El siguiente ejemplo de código registra mapas de clases para las cinco clases de ejemplo, pero etiqueta solo la clase Animal como raíz de la jerarquía de herencia:

BsonClassMap.RegisterClassMap<Animal>(classMap => {
classMap.AutoMap();
classMap.SetIsRootClass(true);
});
BsonClassMap.RegisterClassMap<Cat>();
BsonClassMap.RegisterClassMap<Dog>();
BsonClassMap.RegisterClassMap<Lion>();
BsonClassMap.RegisterClassMap<Tiger>();

Supongamos que etiqueta la clase de ejemplo Animal como raíz de la jerarquía de herencia y, a continuación, crea una instancia de la clase Animal y cada una de sus subclases. Si serializa estos objetos en una sola colección, el controlador .NET/C# aplica HierarchicalDiscriminatorConvention y los documentos BSON correspondientes aparecen de la siguiente manera:

{ _id: ..., _t: "Animal", ... }
{ _id: ..., _t: ["Animal", "Cat"], ... }
{ _id: ..., _t: ["Animal", "Dog"], ... }
{ _id: ..., _t: ["Animal", "Cat", "Lion"], ... }
{ _id: ..., _t: ["Animal", "Cat", "Tiger"], ... }

Importante

Discriminador de clase raíz

Cualquier documento asignado a la clase raíz todavía utiliza un valor de cadena para el campo discriminador.

Al utilizar el HierarchicalDiscriminatorConvention, puede buscar todos los documentos del tipo o subtipo Cat utilizando una única condición booleana, como se muestra en el siguiente ejemplo:

var query = coll.Aggregate().Match(a => a is Cat);

Si está trabajando con datos que no siguen las convenciones utilizadas por el controlador .NET/C# (por ejemplo, datos insertados en MongoDB por otro controlador o asignador de objetos), es posible que deba usar un valor diferente para su campo discriminador para garantizar que sus clases se alineen con esas convenciones.

Si usa el automapper, puede especificar un valor personalizado para el campo discriminador de una clase aplicando el atributo [BsonDiscriminator] a la clase y pasando el valor discriminador personalizado como argumento de cadena. El siguiente ejemplo de código establece el valor del campo discriminador de la clase Animal en "myAnimalClass":

[BsonDiscriminator("myAnimalClass")]
public class Animal
{
}

Si crea un mapa de clases manualmente, llame al método SetDiscriminator() y pase el valor del discriminador personalizado como argumento al registrar el mapa de clases. El siguiente ejemplo de código establece el valor del campo discriminador de la clase Animal en "myAnimalClass":

BsonClassMap.RegisterClassMap<Animal>(classMap =>
{
classMap.AutoMap();
classMap.SetDiscriminator("myAnimalClass");
});

Una instancia de la clase Animal anterior aparece de la siguiente manera después de la serialización:

{ "_id": "...", "_t": "myAnimalClass"}

Volver

POCOs

En esta página