Docs Menu
Docs Home
/ /

POCOs

En esta guía, podrá aprender cómo utilizar "ObjetosCLR/de clasesimples, o POCO, con el controlador .NET/C# para sus operaciones y consultas. Los POCO son objetos de clase simples que no heredan características de ninguna clase base o interfaz específica del framework. Recomendamos usar POCO en su código C# para cumplir con el uso idiomático del controlador y lograr el mejor rendimiento.

Lea esta guía si desea obtener más información sobre cómo usar POCO con el controlador .NET/C# o si debe ajustar el comportamiento de mapeo de campos predeterminado del controlador.

Puedes crear un POCO definiendo una clase simple que no implemente interfaces ni extienda clases de un framework. Al ejecutar una operación, como una lectura o escritura, con un POCO, el controlador serializa o convierte internamente el POCO a BSON.

Seleccione el POCO o la pestaña BSON para ver cómo el controlador serializa una muestra de POCO 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, matrices, listas y cualquier tipo de datos.

Si el comportamiento predeterminado de asignación de campos no satisface sus necesidades, puede especificar un comportamiento personalizado mediante atributos relacionados con la serialización. Estos atributos modifican la forma en que el controlador serializa cada propiedad de su POCO. Esta sección describe algunos atributos comunes relacionados con la serialización.

Si una propiedad es de solo lectura, el automapper 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, aplique la [BsonElement] atribuir 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 ningún 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 agregar una propiedad de solo lectura al registrar el mapa de clase, 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 controlador serializa las propiedades POCO en campos BSON con el mismo nombre y mayúsculas. Para almacenar una propiedad con un nombre diferente, utilice el atributo [BsonElement()]. El siguiente código asigna la propiedad YearBuilt de la clase House al campo year_built del documento BSON serializado:

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

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

Tip

Establecer la convención de nombre de campo personalizado

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, consulte la Secciónde convenciones de la guía de serialización.

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#.

Importante

Serialización de NaN e Infinity

Si intenta serializar o deserializar un valor de punto flotante Infinity o NaN a una representación integral, el controlador lanza un OverflowException.

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

Campos de identificación múltiples

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 del campo _id descrita en esta sección solo se aplica al documento raíz y no se aplica a los documentos anidados.

Cada documento de una colección de MongoDB debe tener un ID único. Al serializar un objeto en una colección, si su propiedad ID contiene el valor predeterminado para su tipo de dato (normalmente null), el controlador .NET/C# no serializa dicho valor. En su lugar, 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 datos del campo Id
Cómo utilizar

Guid

Para utilizar el algoritmo COMB para generar un valor Guid único, aplique 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; }
}

Para obtener más información, consulte la guía de GUID.

ObjectId

El controlador utiliza automáticamente el tipo ObjectIdGenerator para las propiedades de ID con el tipo de datos ObjectId, como el del 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 string único para una propiedad de ID que no esté serializada como ObjectId, aplique el atributo [BsonID(IdGenerator = typeof(StringObjectIdGenerator))] a la propiedad, como se muestra en el siguiente ejemplo de código. El controlador usa el tipo StringObjectIdGenerator para generar un valor ObjectId único, convertirlo en string y asignarlo a la propiedad.

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

BsonObjectId

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

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

Alternativamente, puede especificar un tipo IIdGenerator cuando registre el mapa de clase, 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 múltiples clases

Puede usar el método RegisterIdGenerator() para especificar un único IIdGenerator para todas las propiedades Id de un tipo de dato determinado. El siguiente ejemplo de código indica al controlador que use el tipo CombGuidGenerator para todos los ID 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 de generador IId

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 predeterminado (null), el controlador genera una excepción:

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

Para evitar que el controlador serialice un campo específico, utilice el atributo [BsonIgnore]. El siguiente código muestra cómo evitar que el controlador serialice la propiedad YearBuilt:

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

Incluso si define la propiedad YearBuilt, el campo no se guarda en MongoDB.

Nota

Puede definir un mapa de clases para evitar la serialización de campos específicos. Para obtener más información y ver un ejemplo, consulte la sección "Omitir campos" de la guía de mapeo de clases.

De forma predeterminada, el controlador serializa las propiedades no inicializadas con valores null. Para ignorar las propiedades vacías durante la serialización, utilice el atributo [BsonIgnoreIfNull]. El siguiente código muestra cómo evitar que el controlador serialice la propiedad Style si no está inicializada:

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

También puede indicarle al controlador que ignore una propiedad que contenga un valor null cuando registre el mapa de clase, 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 puede usar el [BsonIgnoreIfNull] atributo ni el SetIgnoreIfNull() método para evitar que se serialicen propiedades de tipo de valor no inicializadas, a menos que las marque como nulas. En su lugar, use el [BsonIgnoreIfDefault] atributo o el método de SetIgnoreIfDefault() mapa de clase, que se describen en la sección "Personalizar valores predeterminados" de esta guía.

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

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

Los siguientes ejemplos de código aplican 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);
});

De forma predeterminada, el controlador .NET/C# serializa todas las propiedades, incluidas aquellas con valores predeterminados. Para indicarle al controlador que ignore una propiedad con el valor predeterminado, utilice 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 dato (0 para las propiedades int), el controlador 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);
});

Puede especificar un valor predeterminado diferente para una propiedad e indicar al controlador que la ignore si contiene dicho valor. Para ello, aplique los 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, tiene el valor predeterminado 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 DateTime, utilice 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; }
}

También 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 puede especificar una o ambas de las opciones DateTime anteriores al registrar el mapa de clase:

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 DateTimeKind enumeración forma parte de .NET Framework. Para obtener más información sobre sus miembros, consulte la documentación de Microsoft sobre la enumeración DateTimeKind.

Para personalizar cómo el controlador .NET/C# serializa las propiedades DateOnly, [BsonDateOnlyOptions()] utilice el atributo y especifique las siguientes configuraciones:

  • Representation:Establezca una instancia BsonType que especifica cómo se almacena el valor DateOnly en MongoDB.

  • DocumentFormatEsta opción solo se aplica si se establece la propiedad Representation en BsonType.Document; de lo contrario, se ignora. Puede establecer DocumentFormat en uno de los siguientes valores de enumeración DateOnlyDocumentFormat:

    • DateTimeTicks (predeterminado): el documento contiene los campos DateTime (BsonType.DateTime) y Ticks (BsonType.Int64)

    • YearMonthDay:El documento contiene los campos Year, Month y Day, que tienen valores BsonType.Int32

En el siguiente ejemplo de código, la clase PatientRecord contiene una propiedad DateOfBirth con un valor DateOnly. El atributo indica al controlador que almacene el valor como un documento anidado que contiene los campos para el año, mes y día especificados.

public class PatientRecord
{
public Guid Id { get; set; }
[BsonDateOnlyOptions(BsonType.Document, DateOnlyDocumentFormat.YearMonthDay)]
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)
);

La enumeración DictionaryRepresentation define los formatos en los que el controlador .NET/C# puede serializar una instancia Dictionary. Esta enumeración incluye los siguientes miembros:

  • 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 en BsonArray un. Cada entrada del diccionario es un anidado de dos elementos BsonArray que contiene la clave y el valor de la entrada.

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

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 puede especificar el formato de serialización de un diccionario cuando registra el mapa de clase, 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 de mapeo de campos personalizados 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 tiempo asociado

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 más información sobre cómo el controlador asigna documentos BSON a POCO, consulte Asignación de clases.

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