Join us at MongoDB.local London on 7 May to unlock new possibilities for your data. Use WEB50 to save 50%.
Register now >
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 de discriminador incluidas con el controlador .NET/C#

  • Cómo crear convenciones de discriminador 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ás utilizando el automapper para mapear tus clases, aplica 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

Aplica el atributo [BsonKnownTypes] solo a las clases principales. Pasa como argumentos solo los tipos que heredan directamente de la clase, no todas las clases hijo en 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 clase

Para obtener más información sobre cómo mapear clases, consulta la Documentación de Asignación 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 de discriminador. En esta sección, puedes aprender sobre las convenciones de discriminador que se incluyen con el .NET/C# Driver 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.

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

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

El ScalarDiscriminatorConvention utiliza valores de discriminador concisos, pero puede ser difícil ejecutar una consulta sobre ellos. Por ejemplo, para encontrar todos los documentos de tipo o subtipo Cat, debes enumerar explícitamente cada clase que buscas:

var query = coll.AsQueryable().Where(
item => item.GetType() == typeof(Cat) ||
item.GetType() == typeof(Lion) ||
item.GetType() == typeof(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.

Nota

Debe especificar los discriminadores jerárquicos en orden de raíz a hoja. Si se invierte el orden, el controlador .NET/C# no podrá resolver el tipo concreto correcto.

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 estás creando un mapa de clase manualmente, llama al método SetIsRootClass() y pasa true como argumento cuando registres el mapa de clase para la clase raíz. El siguiente ejemplo de código registra mapas de clases para las cinco clases de ejemplo, pero solo etiqueta la clase Animal como la 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ás trabajando con datos que no siguen las convenciones utilizadas por el controlador .NET/C#; por ejemplo, datos insertados en MongoDB por otro controlador o un mapeador de objetos, es posible que necesites usar un valor diferente para tu campo discriminador para asegurar que tus clases se alineen con esas convenciones.

Si utilizas el automapper, puedes 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 string. El siguiente ejemplo de código establece el valor del campo discriminador para la clase Animal en "myAnimalClass":

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

Si estás creando un mapa de clases manualmente, llama al método SetDiscriminator() y pasa el valor de discriminador personalizado como argumento al registrar el mapa de clases. El siguiente ejemplo de código establece el valor del campo discriminador para la clase Animal a "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