Overview
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.
Lea esta guía si quiere aprender más sobre cómo usar POCOs con el driver .NET/C# o si necesita ajustar el comportamiento por defecto de mapeo de campos del driver.
Crea un POCO
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.
Serialización personalizada
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 atributos comunes relacionados con la serialización.
Serializar Propiedades de Solo Lectura
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; } [] 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.
Establecer nombres de campos
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; } [] 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 obtener más información sobre las convenciones, consulta el Sección Convenciones de la guía de Serialización.
Seleccionar Representación de Tipo
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; } [] 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#.
Importante
Serializar NaN e Infinito
Si intenta serializar o deserializar un Infinity de punto flotante o valor de NaN en una representación entera, el driver lanza un OverflowException.
Establecer el orden del campo
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; } [] public int YearBuilt { get; set; } [] 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.
Identifica la propiedad Id
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 { [] 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.
Especifica un generador de ID
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 | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| Para usar el algoritmo COMB para generar un valor único de Para generar un valor único Para obtener más información, consulte la guía de GUID. | ||||||||||
| El controlador utiliza automáticamente el tipo | ||||||||||
| Si especifica que una propiedad de ID con el tipo de dato Para generar un valor único de | ||||||||||
| Aplica el atributo |
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 |
|
No todos son ceros |
|
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 { [] public Guid Id { get; set; } }
Omitir campos
Para evitar que el driver serialice un campo especificado, utiliza el atributo [BsonIgnore]. El siguiente código muestra cómo se puede impedir que el controlador serialice la propiedad YearBuilt:
public class House { public Guid Id { get; set; } [] public int YearBuilt { get; set; } public string Style { get; set; } }
Incluso si defines la propiedad YearBuilt, el campo no se guarda en MongoDB.
Nota
Puedes definir un mapa de clase para evitar que campos específicos se serialicen. Para obtener más información y ver un ejemplo, consulta la sección Omitir campos de la guía Mapeo de clases.
Omitir campos vacíos
Por defecto, el controlador serializa las propiedades no inicializadas con valores null. Para omitir las propiedades vacías durante la serialización, utilize el atributo [BsonIgnoreIfNull]. El siguiente código muestra cómo puedes evitar que el controlador serialice la propiedad Style si no está inicializada:
public class House { public Guid Id { get; set; } [] public string Style { get; set; } public int YearBuilt { get; set; } }
También puede indicar al controlador que ignore una propiedad que contenga un valor null cuando registre el mapa de clases, como se muestra en el siguiente ejemplo:
BsonClassMap.RegisterClassMap<House>(classMap => { classMap.AutoMap(); classMap.MapMember(h => h.Style).SetIgnoreIfNull(true); });
Nota
Propiedades de Tipo de Valor
No puedes usar el atributo [BsonIgnoreIfNull] o el método SetIgnoreIfNull() para evitar que las propiedades de tipo valor no inicializadas se serialicen a menos que marques las propiedades como anulables. En su lugar, utilice el atributo [BsonIgnoreIfDefault] o el método de mapeo de clase SetIgnoreIfDefault(), que se describen en la sección Personalizar valores por defecto de esta guía.
Personaliza los valores por defecto
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; } [] 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; } [] 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; } [] [] 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 de1900.Dado que
1900es el valor predeterminado para esta propiedad, el controlador ignorará la propiedad si tiene este valor.
Personalizar la serialización de DateTime
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; } [] 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; } [] 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.
Serialización personalizada de DateOnly
Para personalizar cómo el controlador .NET/C# serializa las propiedades DateOnly, [BsonDateOnlyOptions()] utilice el atributo y especifique las siguientes configuraciones:
Representation: Configurado en una instancia deBsonTypeque especifica cómo se almacena el valor deDateOnlyen MongoDB.DocumentFormat: Esta opción solo se aplica si estableces la propiedadRepresentationenBsonType.Documenty, de lo contrario, se ignora. Puedes establecerDocumentFormaten uno de los siguientes valores de enumeraciónDateOnlyDocumentFormat:DateTimeTicks(por defecto): El documento contieneDateTime(BsonType.DateTime) yTicks(BsonType.Int64) camposYearMonthDayEl documento contiene los camposYear,MonthyDay, que tienen valoresBsonType.Int32
En el siguiente ejemplo de código, la clase PatientRecord contiene una propiedad DateOfBirth que tiene un valor DateOnly. El atributo indica al controlador que almacene el valor como un documento anidado que contiene campos para el año, mes y día dados.
public class PatientRecord { public Guid Id { get; set; } [] public DateOnly DateOfBirth { get; set; } }
Tip
Utilice DateOnlySerializer para establecer el comportamiento global
En lugar de utilizar el atributo [BsonDateOnlyOptions()] en el nivel de propiedad, puede registrar un objeto DateOnlySerializer para aplicar el comportamiento de serialización globalmente:
BsonSerializer.RegisterSerializer( new DateOnlySerializer(BsonType.Document, DateOnlyDocumentFormat.YearMonthDay) );
Personalizar la serialización del diccionario
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
DictionaryBsonDocumentcomo. Cada entrada del diccionario es unBsonElementcon 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 sonBsonElementnombres válidos.ArrayOfArrays: el controlador serializa el diccionario a un
BsonArray. Cada entrada en el diccionario es unBsonArrayanidado 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 unBsonDocumentanidado 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 unArrayOfArrays.
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; } [] 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)); });
Ejemplo
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 campoPricecomo un tipo BSONDouble[BsonDefaultValue()]que establece la propiedadNameen"Generic item"si no se le ha asignado ningún valor[BsonDateTimeOptions(DateOnly = true)]que especifica que la propiedadDateTimerepresenta solo un valor de fecha, sin ninguna hora asociada
public class Clothing { public ObjectId Id { get; set; } [] [] public string Name { get; set; } [] public bool InStock { get; set; } [] [] public decimal Price { get; set; } [] public List<string> ColorSelection { get; set; } [] [] public DateTime ListedDate { get; set; } [] 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\"" } }
Información Adicional
Para obtener una lista completa de los atributos relacionados con la serialización, consulte la documentación de la API Serialization.Attributes.
Para obtener más información sobre cómo el controlador asigna documentos BSON a POCOs, consulta Asignación de clase.
Documentación de la API
Para aprender más sobre cualquiera de los métodos o tipos analizados en esta guía, consulta la siguiente documentación de API: