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
/ /

POCOs

En esta guía, podrá aprender cómo utilizar "Objetos CLR/Clase Previstos (Plain Old CLR/Class Objects)", o POCOs, con el Driver de .NET/C# para sus operaciones y consultas. Los POCO son objetos de clase simples que no heredan funcionalidades de ninguna clase base o interfaz específica del framework. Te recomendamos usar POCO en tu código C# para adherir a un uso idiomático del controlador y lograr el mejor rendimiento.

Deberías leer esta guía si quieres aprender más sobre cómo usar POCOs con el driver .NET/C# o si necesitas ajustar el comportamiento de mapeo de campos por defecto del driver.

Puedes crear un POCO definiendo una clase sencilla que no implemente interfaces ni extienda clases de un framework. Cuando ejecutas una operación como una lectura o guardar utilizando un POCO, el driver internamente serializa, o convierte, el POCO en BSON.

Selecciona el POCO o la BSON pestaña para ver cómo el controlador serializa un POCO de muestra a BSON:

public class Clothing
{
public ObjectId Id { get; set; }
public string Name { get; set; }
public bool InStock { get; set; }
public double Price { get; set; }
public List<string> ColorSelection { get; set; }
}
{
"_id": ObjectId("..."),
"Name": "Long Sleeve Shirt",
"InStock": true,
"Price": 17.99,
"ColorSelection": [ "black", "navy", "red" ]
}

Puede definir un POCO con cualquier estructura de objeto que se adapte a sus necesidades, incluidos objetos anidados, arreglos, listas y cualquier tipo de dato.

Si el comportamiento de mapeo de campos por defecto no se ajusta a sus necesidades, puede especificar un comportamiento personalizado mediante los atributos relacionados con la serialización. Estos atributos cambian la forma en que el controlador serializa cada propiedad de tu POCO. Esta sección describe algunos de los atributos comunes relacionados con la serialización.

Si una propiedad es de solo lectura, el automapeador no la incluye en el mapa de clases para la serialización. Para forzar al automapper a incluir una propiedad en el mapa de clases, aplica el [BsonElement] atributo a la propiedad.

El siguiente ejemplo de código aplica el atributo [BsonElement] a la propiedad Upc de la clase Clothing. Upc es una propiedad de solo lectura porque tiene un método get pero no un método set.

public class Clothing
{
public ObjectId Id { get; set; }
public string Name { get; set; }
public bool InStock { get; set; }
public double Price { get; set; }
public List<string> ColorSelection { get; set; }
[BsonElement]
public int Upc { get; }
}

También puede añadir una propiedad de solo lectura al registrar el mapa de clases, como se muestra en el siguiente ejemplo:

BsonClassMap.RegisterClassMap<Clothing>(classMap =>
{
classMap.AutoMap();
classMap.MapProperty(c => c.Upc);
});

Nota

Cuando el controlador .NET/C# serializa una propiedad de solo lectura, la propiedad y su valor se almacenan en la base de datos, pero nunca se deserializan nuevamente.

El driver serializa las propiedades POCO a campos BSON con el mismo nombre de campo y uso de mayúsculas. Para almacenar una propiedad bajo un nombre diferente, utiliza el atributo [BsonElement()]. El siguiente código asigna la propiedad YearBuilt de la clase House al campo year_built en el documento BSON serializado:

public class House
{
public Guid Id { get; set; }
[BsonElement("year_built")]
public int YearBuilt { get; set; }
}

Aunque es común utilizar la convención de nomenclatura Pascal case al definir clases C#, el uso del atributo [BsonElement()] permite seleccionar una convención de nomenclatura diferente o personalizada en su colección de MongoDB.

Tip

Establecer la Convención de Nombres de Campos Personalizados

Si desea serializar cada propiedad con un nombre de campo personalizado, puede definir un atributo ConventionPack en lugar de usar el atributo [BsonElement()]. Por ejemplo, si define su clase usando la convención de nomenclatura Pascal, puede usar el siguiente código para usar nombres de campo CamelCase en el documento serializado:

var camelCaseConvention = new ConventionPack { new CamelCaseElementNameConvention() };
ConventionRegistry.Register("CamelCase", camelCaseConvention, type => true);

Para serializar una propiedad de C# a un tipo BSON específico, use el atributo [BsonRepresentation()]. Esto solo funciona si el tipo primitivo de C# es convertible al tipo BSON especificado.

En el siguiente ejemplo de código, el controlador serializa la propiedad YearBuilt, definida como char en C#, como un tipo BSON Int32:

public class House
{
public Guid Id { get; set; }
[BsonRepresentation(BsonType.Int32)]
public char YearBuilt { get; set; }
}

Para obtener más información sobre las conversiones de tipos válidas, consulte la Especificación de conversiones de C#.

El controlador serializa las propiedades en los campos BSON en el orden en que se especifican en el POCO. Para almacenar las propiedades en un orden personalizado que coincida con un esquema existente, puede especificar el parámetro con nombre Order en el atributo [BsonElement()]. En el siguiente ejemplo de código, el controlador almacena la propiedad YearBuilt después de la propiedad Style:

public class House
{
public Guid Id { get; set; }
[BsonElement(Order = 2)]
public int YearBuilt { get; set; }
[BsonElement(Order = 1)]
public string Style { get; set; }
}

Si alguna propiedad no tiene explícitamente un Order, el driver las serializará en el orden por defecto después de aquellas que sí lo tengan.

Por defecto, el controlador asigna cualquier propiedad pública llamada Id, id, o _id al campo BSON _id. Para seleccionar explícitamente la propiedad que se asignará al campo _id, utiliza el atributo [BsonId()]. El siguiente ejemplo de código asigna la propiedad Identifier al campo _id:

public class House
{
[BsonId]
public string Identifier { get; set; }
}

Advertencia

Varios campos de ID

Si identifica más de una propiedad como el campo _id mediante el atributo [BsonId()], el controlador genera un error DuplicateBsonMemberMapAttributeException. Si especifica el mismo campo de base de datos más de una vez (por ejemplo, si su POCO incluye las propiedades Id y _id), el controlador genera un error BsonSerializationException.

Nota

Identificadores de documentos anidados

La lógica de mapeo de campos _id descrita en esta sección solo se aplica al documento raíz y no a los documentos anidados.

Cada documento en una colección de MongoDB debe tener un ID único. Cuando se serializa un objeto en una colección, si su propiedad ID contiene el valor predeterminado para su tipo de dato (generalmente null), el controlador de .NET/C# no serializa el valor predeterminado. En su lugar, el controlador intenta generar un valor de ID único y asignarlo a la propiedad.

Para habilitar la generación de ID para una propiedad, debe especificar el generador de ID que el controlador utiliza para ella. Puede hacerlo aplicando el atributo [BsonId] a la propiedad y pasando el argumento IdGenerator para especificar el tipo de generador. La siguiente tabla describe los generadores de ID disponibles en el controlador .NET/C#:

Tipo de dato del campo Id
Cómo utilizar

Guid

Para usar el algoritmo COMB para generar un valor único de Guid, aplica el atributo [BsonId(IdGenerator = typeof(CombGuidGenerator))] a la propiedad ID, como se muestra en el siguiente ejemplo:

public class House
{
[BsonId(IdGenerator = typeof(CombGuidGenerator))]
public Guid Id { get; set; }
}

Para generar un valor único Guid sin el algoritmo COMB, no aplique el atributo anterior a la propiedad de ID. El controlador utiliza automáticamente el tipo GuidGenerator para generar un valor único para la propiedad ID.

public class House
{
public Guid Id { get; set; }
}

ObjectId

El controlador utiliza automáticamente el tipo ObjectIdGenerator para las propiedades de identificación con el tipo de datos ObjectId, como en el siguiente ejemplo de código:

public class House
{
public ObjectId Id { get; set; }
}

string

Si especifica que una propiedad de ID con el tipo de dato string se serializa como un ObjectId, el controlador utilizará automáticamente el StringObjectIdGenerator para generar un valor string único para la propiedad. En el siguiente ejemplo de código, el controlador utiliza el StringObjectIdGenerator para la propiedad Id:

public class House
{
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
}

Para generar un valor único de string para una propiedad de ID que no se serializa como un ObjectId, aplique el atributo [BsonID(IdGenerator = typeof(StringObjectIdGenerator))] a la propiedad, como se muestra en el siguiente ejemplo de código. El controlador utiliza el tipo StringObjectIdGenerator para generar un valor único de ObjectId, convertirlo en un string y asignarlo a la propiedad.

public class House
{
[BsonId(IdGenerator = typeof(StringObjectIdGenerator))]
public string Id { get; set; }
}

BsonObjectId

Aplica el atributo [BsonId(IdGenerator = typeof(BsonObjectIdGenerator))] a la propiedad ID, como se muestra en el siguiente ejemplo de código. El controlador utiliza el tipo BsonObjectIdGenerator para generar un valor único de BsonObjectId para la propiedad.

public class House
{
[BsonId(IdGenerator = typeof(BsonObjectIdGenerator))]
public BsonObjectId Id { get; set; }
}

Como alternativa, puedes especificar un tipo de IIdGenerator al registrar el mapa de clases, como se muestra en el siguiente ejemplo:

BsonClassMap.RegisterClassMap<House>(classMap =>
{
classMap.AutoMap();
classMap.MapIdMember(h => h.Id).SetIdGenerator(CombGuidGenerator.Instance);
});

Tip

Especificar un IIdGenerator para varias clases

Puede usar el método RegisterIdGenerator() para especificar un único IIdGenerator para todas las propiedades Id de un determinado tipo de datos. El siguiente ejemplo de código indica al driver que use el tipo CombGuidGenerator para todos los IDs Guid:

BsonSerializer.RegisterIdGenerator(
typeof(Guid),
CombGuidGenerator.Instance
);

El controlador .NET/C# también incluye tipos IIdGenerator que validan la propiedad Id y generan una excepción si el ID no es válido. La siguiente tabla enumera estos tipos:

Validación de identidad
Tipo IIdGenerator

No nulo

NullIdChecker

No todos son ceros

ZeroIdChecker<T>

En el siguiente ejemplo de código, si la propiedad Id de la clase House contiene el valor por defecto (null), el driver lanza una excepción:

public class House
{
[BsonId(IdGenerator = typeof(NullIdChecker))]
public Guid Id { get; set; }
}

Por defecto, el driver serializa las propiedades indefinidas en campos con valores null. Para ignorar propiedades indefinidas durante la serialización, utiliza el atributo [BsonIgnore]. El siguiente código muestra cómo se puede evitar que el controlador serialice la propiedad YearBuilt si esta es indefinida:

public class House
{
public Guid Id { get; set; }
[BsonIgnore]
public int YearBuilt { get; set; }
public string Style { get; set; }
}

En C#, una propiedad tiene un valor por defecto hasta que se le asigne uno. El valor por defecto depende del tipo de dato de la propiedad. Por ejemplo, el valor por defecto para una propiedad de tipo referencia es null.

Para especificar un valor predeterminado diferente para una propiedad, aplica el atributo [BsonDefaultValue()] a la propiedad y pasa el valor predeterminado deseado como argumento.

El siguiente ejemplo de código aplica el atributo [BsonDefaultValue()] a la propiedad YearBuilt. Hasta que se le asigne un valor a esta propiedad, su valor es 1900.

public class House
{
public Guid Id { get; set; }
[BsonDefaultValue(1900)]
public int YearBuilt { get; set; }
}

También puede especificar un valor predeterminado diferente para una propiedad cuando registra el mapa de clase, como se muestra en el siguiente ejemplo:

BsonClassMap.RegisterClassMap<House>(classMap =>
{
classMap.AutoMap();
classMap.MapMember(h => h.YearBuilt).SetDefaultValue(1900);
});

Por defecto, el Driver .NET/C# serializa todas las propiedades, incluidas aquellas que contienen valores predeterminados. Para indicar al driver que ignore una propiedad que tiene el valor por defecto, utiliza el atributo [BsonIgnoreIfDefault].

El siguiente ejemplo de código aplica el atributo [BsonIgnoreIfDefault] a la propiedad YearBuilt. Si el valor de esta propiedad es el predeterminado para su tipo de datos (0 para las propiedades de int), el driver no lo serializará.

public class House
{
public Guid Id { get; set; }
[BsonIgnoreIfDefault]
public int YearBuilt { get; set; }
}

También puede indicarle al controlador que ignore una propiedad que contenga el valor predeterminado cuando registre el mapa de clase, como se muestra en el siguiente ejemplo:

BsonClassMap.RegisterClassMap<House>(classMap =>
{
classMap.AutoMap();
classMap.MapMember(h => h.YearBuilt).SetIgnoreIfDefault(true);
});

Se puede tanto especificar un valor por defecto diferente para una propiedad como indicar al driver que ignore la propiedad si contiene este valor por defecto. Para ello, aplique ambos atributos, [BsonDefaultValue()] y [BsonIgnoreIfDefault], a la propiedad, como se muestra en el siguiente ejemplo de código:

public class House
{
public Guid Id { get; set; }
[BsonDefaultValue(1900)]
[BsonIgnoreIfDefault]
public int YearBuilt { get; set; }
}

El ejemplo de código anterior establece el siguiente comportamiento de serialización:

  • Si no se ha asignado un valor a la propiedad YearBuilt, esta tendrá el valor por defecto especificado de 1900.

  • Dado que 1900 es el valor predeterminado para esta propiedad, el controlador ignorará la propiedad si tiene este valor.

Para personalizar cómo el controlador .NET/C# serializa las propiedades de DateTime, use el atributo [BsonDateTimeOptions()] y especifique la configuración deseada como argumento.

Si una propiedad DateTime representa solo una fecha, puede aplicarle el atributo [BsonDateTimeOptions(DateOnly = true)]. Si lo hace, el controlador no realizará ninguna conversión de zona horaria en el valor.

En el siguiente ejemplo de código, la clase PatientRecord usa un DateTime para la propiedad DateOfBirth. El atributo [BsonDateTimeOptions(DateOnly = true)] indica que la propiedad solo contiene una fecha.

public class PatientRecord
{
public Guid Id { get; set; }
[BsonDateTimeOptions(DateOnly = true)]
public DateTime DateOfBirth { get; set; }
}

Puede usar el atributo [BsonDateTimeOptions()] para especificar el DateTimeKind de una propiedad DateTime. En el siguiente ejemplo de código, la clase PatientRecord tiene una propiedad AppointmentTime de tipo DateTime. El atributo [BsonDateTimeOptions(Kind = DateTimeKind.Local)] indica que el componente de tiempo del valor de la propiedad está en hora local. Cuando el controlador serializa esta propiedad, convierte la hora a UTC, el formato estándar para las horas almacenadas en MongoDB.

public class PatientRecord
{
public Guid Id { get; set; }
[BsonDateTimeOptions(Kind = DateTimeKind.Local)]
public DateTime AppointmentTime { get; set; }
}

También puedes especificar una o las dos de las opciones anteriores DateTime al registrar el mapa de clases:

BsonClassMap.RegisterClassMap<House>(classMap =>
{
classMap.AutoMap();
classMap.MapMember(p => p.DateOfBirth)
.SetSerializer(new DateTimeSerializer(dateOnly: true));
classMap.MapMember(p => p.AppointmentTime)
.SetSerializer(new DateTimeSerializer(DateTimeKind.Local));
});

Tip

DateTimeKind Values

La enumeración DateTimeKind forma parte del framework .NET. Para obtener más información sobre sus miembros, consulte la documentación de Microsoft para el enum DateTimeKind.

El enumerador DictionaryRepresentation define los formatos en los que el Driver .NET/C# puede serializar una instancia Dictionary. Este enumerado incluye los siguientes nodos:

  • Documento: (Predeterminado) El controlador serializa Dictionary BsonDocumentcomo. Cada entrada del diccionario es un BsonElement con un nombre igual a la clave de la entrada y un valor igual al valor de la entrada. Esta representación solo se puede usar cuando todas las claves del diccionario son cadenas que también son BsonElement nombres válidos.

  • ArrayOfArrays: el controlador serializa el diccionario a un BsonArray. Cada entrada en el diccionario es un BsonArray anidado de dos elementos que contiene la clave de la entrada y el valor de la entrada.

  • ArrayOfDocuments: El controlador serializa el diccionario en un BsonArray. Cada entrada en el diccionario es un BsonDocument anidado de la forma { k : key, v : value }. Debido a que las claves y los valores están etiquetados con nombres de elementos, puedes consultar este formato de manera más intuitiva que un ArrayOfArrays.

En el siguiente ejemplo de código, la propiedad RoomSizes es un diccionario que contiene cada habitación de una casa y su tamaño correspondiente. El atributo [BsonDictionaryOptions()] indica al controlador .NET/C# que serialice esta propiedad en un objeto BsonArray y cada entrada del diccionario en un objeto BsonDocument con la forma { k : "<room>", v : <size> }.

public class House
{
public Guid Id { get; set; }
[BsonDictionaryOptions(DictionaryRepresentation.ArrayOfDocuments)]
public Dictionary<string, float> RoomSizes { get; set; }
}

También se puede especificar el formato de serialización de un diccionario al registrar el mapa de clases, como se muestra en el siguiente ejemplo:

BsonClassMap.RegisterClassMap<House>(classMap =>
{
classMap.AutoMap();
classMAp.MapMember(h => h.RoomSizes)
.SetSerializer(new DictionaryInterfaceImplementerSerializer<Dictionary<string, float>>
(DictionaryRepresentation.ArrayOfDocuments));
});

El siguiente ejemplo muestra cómo insertar un documento Clothing con especificaciones personalizadas de asignación de campos en MongoDB.

El siguiente código define la clase Clothing con estos atributos relacionados con la serialización:

  • [BsonElement()], que especifica nombres de campos personalizados en la convención de nomenclatura Camel Case

  • [BsonRepresentation()]que especifica la serialización del campo Price como un tipo BSON Double

  • [BsonDefaultValue()]que establece la propiedad Name en "Generic item" si no se le ha asignado ningún valor

  • [BsonDateTimeOptions(DateOnly = true)]que especifica que la propiedad DateTime representa solo un valor de fecha, sin ninguna hora asociada

public class Clothing
{
public ObjectId Id { get; set; }
[BsonElement("name")]
[BsonDefaultValue("Generic item")]
public string Name { get; set; }
[BsonElement("inStock")]
public bool InStock { get; set; }
[BsonElement("price")]
[BsonRepresentation(BsonType.Decimal128)]
public decimal Price { get; set; }
[BsonElement("colorSelection")]
public List<string> ColorSelection { get; set; }
[BsonElement("listedDate")]
[BsonDateTimeOptions(DateOnly = true)]
public DateTime ListedDate { get; set; }
[BsonElement("sizeGuide")]
public Dictionary<string, string> SizeGuide { get; set; }
}

El siguiente código instancia un objeto Clothing e inserta el documento en una colección:

var doc = new Clothing
{
Name = "Denim Jacket",
InStock = false,
Price = 32.99m,
ColorSelection = new List<string> { "dark wash", "light wash" },
ListedDate = DateTime.Parse("Jan 1, 2007"),
SizeGuide = new Dictionary<string, string>()
{
{"Small", "Chest: 38\", Waist: 38\", Shoulders: 15\""},
{"Medium", "Chest: 40\", Waist: 40\", Shoulders: 15.5\""},
{"Large", "Chest: 42\", Waist: 40\", Shoulders: 16\""}
}
};
_myColl.InsertOne(doc);

La representación BSON del documento insertado se ve así:

{
"_id": ObjectId("..."),
"name": "Denim Jacket",
"inStock": false,
"price": 32.99,
"colorSelection": [ "dark wash", "light wash" ],
"listedDate" : ISODate("2007-01-01T00:00:00Z"),
"sizeGuide" : {
"Small" : "Chest: 38\", Waist: 38\", Shoulders: 15\"",
"Medium" : "Chest: 40\", Waist: 40\", Shoulders: 15.5\"",
"Large" : "Chest: 42\", Waist: 40\", Shoulders: 16\""
}
}

Para obtener una lista completa de los atributos relacionados con la serialización, consulte la documentación de la API Serialization.Attributes.

Para obtener ejemplos adicionales de operaciones de lectura y escritura mediante POCO, consultar el Ejemplos de uso o las Páginas de Fundamentos de CRUD.

Para obtener más información sobre cómo el controlador asigna documentos BSON a POCOs, consulta Asignación de clase.

Para aprender más sobre cualquiera de los métodos o tipos analizados en esta guía, consulta la siguiente documentación de API:

Volver

Mapeo de clases

En esta página