Menu Docs
Página inicial do Docs
/ / /
C#/.NET
/ /

POCOs

Nesta página

  • Visão geral
  • Crie um POCO
  • Serialização personalizada
  • Serialize propriedades somente para leitura
  • Defina nomes de campo
  • Selecione o tipo de representação
  • Defina a ordem dos campos
  • Identifique a propriedade Id
  • Omita campos vazios
  • Personalize valores padrão
  • Personalize a serialização de DateTime
  • Personalize a serialização do dicionário
  • Exemplo
  • Informações adicionais
  • Documentação da API

Neste guia, você aprenderá a usar "Plain Old CLR/Class Objects", ou PoCOs, com o driver .NET/C# para suas operações e queries. POCOs são objetos de classe simples que não herdam recursos de nenhuma classe base ou interface específica de framework. Recomendamos usar POCOs em seu código C# para aderir ao uso idiomático do driver e obter o melhor desempenho.

Leia este guia para saber mais sobre como usar POCOs com o driver .NET/C#, ou se precisar ajustar o comportamento de mapeamento de campo padrão do driver.

Você pode criar um POCO definindo uma classe simples que não implemente interfaces ou estenda classes de um framework. Ao executar uma operação como uma leitura ou gravação utilizando um POCO, o driver internamente serializa ou converte o POCO para BSON.

Selecione a aba POCO ou BSON para ver como o driver serializa uma amostra de POCO para 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" ]
}

Você pode definir um POCO com qualquer estrutura de objeto que atenda às suas necessidades, incluindo objetos aninhados, arrays, listas e quaisquer tipos de dados.

Se o comportamento de mapeamento de campo padrão não atender às suas necessidades, você poderá especificar o comportamento personalizado utilizando atributos relacionados à serialização. Esses atributos alteram a maneira como o driver serializa cada propriedade do seu POCO. Esta seção descreve alguns dos atributos comuns relacionados à serialização.

Se uma propriedade for somente para leitura, o automatizador não a incluirá no mapa de classes para a serialização. Para forçar o automapper a incluir uma propriedade no mapa de classe, aplique o atributo [BsonElement] na propriedade.

O exemplo de código abaixo aplica o atributo [BsonElement] à propriedade Upc da classe Clothing. Upc é uma propriedade somente para leitura, pois tem um método get mas nenhum 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; }
}

Você também pode adicionar uma propriedade somente para leitura ao registrar o mapa de classe, conforme mostrado no exemplo abaixo:

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

Observação

Quando o driver .NET/C# serializa uma propriedade somente para leitura, a propriedade e seu valor são armazenados no banco de dados, mas nunca são desserializados novamente.

O driver serializa propriedades POCO para campos BSON com o mesmo nome de campo e capitalização. Para armazenar uma propriedade com outro nome, use o atributo [BsonElement()]. O código abaixo mapeia a propriedade YearBuilt da classe House para o campo year_built no documento BSON serializado:

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

Embora seja comum usar a convenção de nomenclatura Pascal case ao definir classes C#, usar o atributo [BsonElement()] permite selecionar uma convenção de nome diferente ou personalizada em sua coleção do MongoDB.

Dica

Definir convenção de nomenclatura de campo personalizado

Para serializar cada propriedade com um nome de campo personalizado, você pode definir um ConventionPack em vez de usar o atributo [BsonElement()]. Por exemplo, ao definir a classe usando a convenção de nomenclatura Pascal case, você poderá usar o código abaixo para optar por nomes de campo de Camel case no documento serializado:

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

Para serializar uma propriedade C# para um tipo BSON específico, use o atributo [BsonRepresentation()]. Isso funciona somente se o tipo primitivo C# for convertível no tipo BSON que você especificar.

No exemplo de código a seguir, o driver serializa a propriedade YearBuilt , definida como char em C#, como um tipo BSON Int32:

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

Para obter mais informações sobre conversões de tipo válidas, consulte a Especificação de conversões C#.

Importante

Serializando NaN e Infinity

Se você tentar serializar ou desserializar um valor Infinity ou NaN de ponto flutuante em uma representação integral, o driver lançará um OverflowException.

O driver serializa propriedades para campos BSON na ordem em que são especificados no POCO. Para armazenar propriedades em uma ordem personalizada para corresponder a um esquema existente, você pode especificar o parâmetro nomeado Order no atributo [BsonElement()]. No exemplo de código abaixo, o driver armazena a propriedade YearBuilt após a propriedade 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; }
}

Se alguma propriedade não tiver um Order explícito, o driver as serializará na ordem padrão depois de encontrar as que tiverem.

Por padrão, o driver mapeia qualquer propriedade pública denominada Id, id ou _id para o campo BSON _id. Para selecionar explicitamente a propriedade a ser mapeada para o campo _id, use o atributo [BsonId()]. O exemplo de código abaixo mapeia a propriedade Identifier para o campo _id:

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

Aviso

Vários campos de ID

Se você identificar mais de uma propriedade como o campo _id usando o atributo [BsonId()], o driver lançará um DuplicateBsonMemberMapAttributeException. Se você especificar o mesmo campo de banco de dados mais de uma vez (por exemplo, se o POCO incluir propriedades denominadas Id e _id), o driver lançará um BsonSerializationException.

Observação

IDs de documentos aninhados

A lógica de mapeamento de campo _id descrita nesta seção se aplica somente ao documento raiz e não se aplica a documentos aninhados.

Cada documento em uma coleção MongoDB deve ter um ID exclusivo. Quando você serializa um objeto para uma coleção, se sua propriedade ID contiver o valor padrão para seu tipo de dados (geralmente null), o driver .NET/C# não serializará o valor padrão. Em vez disso, o driver tenta gerar um valor de ID exclusivo e atribuí-lo à propriedade.

Para habilitar a geração de ID para uma propriedade, você deve especificar o gerador de ID que o driver utiliza para a propriedade. Você pode fazer isso aplicando o atributo [BsonId] à propriedade e passando o argumento IdGenerator para especificar o tipo de gerador. A tabela a seguir descreve os geradores de ID disponíveis no driver .NET/C#:

Tipo de dados do campo de ID
How to Use

Guid

Para usar o algoritmo COMB para gerar um valor Guid exclusivo, aplique o atributo [BsonId(IdGenerator = typeof(CombGuidGenerator))] à propriedade ID, conforme mostrado no exemplo a seguir:

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

Para gerar um valor Guid único sem o algoritmo COMB, não aplique o atributo anterior à propriedade ID. O driver utiliza automaticamente o tipo GuidGenerator para gerar um valor único para a propriedade ID.

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

ObjectId

O driver usa automaticamente o tipo ObjectIdGenerator para propriedades ID com o tipo de dados ObjectId, como o do exemplo de código a seguir:

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

string

Se você especificar que uma propriedade ID com o tipo de dados string é serializada como ObjectId, o driver usará automaticamente o StringObjectIdGenerator para gerar um valor string exclusivo para a propriedade. No seguinte exemplo de código , o driver utiliza o StringObjectIdGenerator para a propriedade Id :

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

Para gerar um valor string exclusivo para uma propriedade ID que não seja serializada como ObjectId, aplique o atributo [BsonID(IdGenerator = typeof(StringObjectIdGenerator))] à propriedade, conforme mostrado no exemplo de código a seguir. O driver utiliza o tipo StringObjectIdGenerator para gerar um valor de ObjectId único, convertê-lo em um string e atribuí-lo à propriedade.

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

BsonObjectId

Aplique o atributo [BsonId(IdGenerator = typeof(BsonObjectIdGenerator))] à propriedade ID, conforme mostrado no exemplo de código a seguir. O driver utiliza o tipo BsonObjectIdGenerator para gerar um valor de BsonObjectId único para a propriedade.

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

Alternativamente, você pode especificar um tipo IIdGenerator ao registrar o mapa de classe , como mostrado no seguinte exemplo:

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

Dica

Especifique um IIdGenerator para várias classes

Você pode usar o método RegisterIdGenerator() para especificar um único IIdGenerator para todas as propriedades do Id de um determinado tipo de dados. O exemplo de código abaixo instrui o driver a usar o tipo CombGuidGenerator para todos os IDs Guid :

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

O driver .NET/C# também inclui tipos de IIdGenerator que validam a propriedade Id e lançam uma exceção se o ID for inválido. A tabela a seguir lista estes tipos:

Validação de ID
Tipo IIDGenerator

Não é nulo

NullIdChecker

Nem todos zeros

ZeroIdChecker<T>

No exemplo de código abaixo, se a propriedade Id da classe House contiver o valor padrão (null), o driver lançará uma exceção:

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

Por padrão, o driver serializa propriedades indefinidas para campos com valores null. Para ignorar propriedades indefinidas durante a serialização, use o atributo [BsonIgnore]. O código abaixo mostra como evitar que o driver serialize a propriedade YearBuilt se ela for indefinida:

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

Em C#, uma propriedade possui um valor padrão até você atribuir um valor a ela. O valor padrão depende do tipo de dados da propriedade. Por exemplo, o valor padrão para uma propriedade de tipo de referência é null.

Para especificar outro valor padrão para uma propriedade, aplique o atributo [BsonDefaultValue()] na propriedade e passe o valor padrão desejado como um argumento.

Os exemplos de código abaixo aplicam o atributo [BsonDefaultValue()] à propriedade YearBuilt. Até que essa propriedade receba um valor, seu valor será 1900.

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

Você também pode especificar outro valor padrão para uma propriedade ao registrar o mapa de classe, conforme o exemplo abaixo:

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

Por padrão, o Driver .NET/C# serializa todas as propriedades, incluindo aquelas que contêm valores padrão. Para instruir o driver a ignorar uma propriedade que tenha o valor padrão, utilize o atributo [BsonIgnoreIfDefault].

O exemplo de código abaixo aplica o atributo [BsonIgnoreIfDefault] na propriedade YearBuilt. Se o valor desta propriedade for o padrão para seu tipo de dados (0 para propriedades do int), o driver não fará a serialização.

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

Você também pode instruir o driver a ignorar uma propriedade que contém o valor padrão ao registrar o mapa de classe, conforme o exemplo abaixo:

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

Ambos podem especificar outro valor predefinido para uma propriedade e instruir o driver a ignorar a propriedade se contiver este valor predefinido. Para tal, aplique os atributos [BsonDefaultValue()] e [BsonIgnoreIfDefault] à propriedade, conforme o exemplo de código abaixo:

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

O exemplo de código anterior define o seguinte comportamento de serialização:

  • Se um valor não tiver sido atribuído à propriedade YearBuilt, ele terá um valor padrão especificado de 1900.

  • Uma vez que 1900 é o valor predefinido para esta propriedade, o driver irá ignorar a propriedade se tiver este valor.

Para personalizar como o Driver .NET/C# serializa as propriedades do DateTime, utilize o atributo [BsonDateTimeOptions()] e especifique a configuração desejada como um argumento.

Se uma propriedade DateTime representar somente uma data, você poderá aplicar o atributo [BsonDateTimeOptions(DateOnly = true)]. Se você fizer isso, o driver não executará nenhuma conversão de fuso horário no valor.

No exemplo de código abaixo, a classe PatientRecord usa um DateTime para a propriedade DateOfBirth. O atributo [BsonDateTimeOptions(DateOnly = true)] indica que a propriedade contém apenas uma data.

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

Você também pode usar o atributo [BsonDateTimeOptions()] para especificar o DateTimeKind de uma propriedade DateTime. No exemplo de código abaixo, a classe PatientRecord tem uma propriedade AppointmentTime do tipo DateTime. O atributo [BsonDateTimeOptions(Kind = DateTimeKind.Local)] indica que o componente de tempo do valor da propriedade está na hora local. Quando o driver serializa essa propriedade, ele converte a hora para UTC, o formato padrão para horas armazenadas no MongoDB.

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

Você também pode especificar uma ou ambas as opções do DateTime anteriores ao registrar o mapa de classe:

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));
});

Dica

Valores de DateTimeKind

a enumeração de DateTimeKind faz parte do framework .NET. Para mais informações sobre seus nós, consulte a documentação da Microsoft de enumeração de DateTimeKind.

a enumeração de DictionaryRepresentation define os formatos aos quais o driver .NET/C# pode serializar uma instância do Dictionary. Esta enumeração inclui os seguintes nós:

  • Documento: (Padrão) o driver serializa o Dictionary para um BsonDocument. Cada entrada no dicionário é um BsonElement com um nome igual à chave da entrada e um valor igual ao valor da entrada. Você pode usar essa representação somente quando todas as chaves do dicionário forem strings que também sejam nomes BsonElement válidos.

  • ArrayOfArrays: o driver serializa o dicionário para um BsonArray. Cada entrada no dicionário é um BsonArray aninhado de dois elementos que contém a chave e o valor da entrada.

  • ArrayOfDocuments: o driver serializa o dicionário para um BsonArray. Cada entrada no dicionário é um BsonDocument aninhado no formato { k : key, v : value }. Como as chaves e os valores são marcados com nomes de elementos, você pode fazer consulta desse formato de forma mais intuitiva do que um ArrayOfArrays.

No exemplo de código abaixo, a propriedade RoomSizes é um dicionário que contém cada quarto de uma casa e seu tamanho correspondente. O atributo [BsonDictionaryOptions()] instrui o driver .NET/C# a serializar esta propriedade para um objeto BsonArray e cada entrada no dicionário para um BsonDocument do formulário { k : "<room>", v : <size> }.

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

Você também pode especificar o formato de serialização de um dicionário ao registrar o mapa de classe, conforme o exemplo abaixo:

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

O exemplo abaixo mostra como inserir um documento de Clothing com especificações de mapeamento de campo personalizadas no MongoDB.

O código abaixo define a classe Clothing com estes atributos relacionados à serialização:

  • [BsonElement()], que especifica os nomes de campos personalizados na convenção de nomenclatura Camel case

  • [BsonRepresentation()], que especifica a serialização do campo Price como um tipo Double de BSON

  • [BsonDefaultValue()], que define a propriedade Name como "Generic item" se nenhum valor tiver sido atribuído a ela

  • [BsonDateTimeOptions(DateOnly = true)], que especifica que a propriedade DateTime representa somente um valor de data, sem hora associada

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; }
}

O código abaixo instancia um objeto Clothing e insere o documento em uma coleção:

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);

A representação BSON do documento inserido é semelhante a esta:

{
"_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 obter uma lista completa de atributos relacionados à serialização, consulte a documentação da API Serialization.Attributes.

Para mais exemplos de operações de leitura e gravação usando POCOs, consulte os exemplos de uso ou as Páginas de introdução a CRUD.

Para saber mais sobre como o driver mapeia documentos BSON para POCOs, consulte Mapeamento de classe.

Para saber mais sobre qualquer um dos métodos ou tipos discutidos neste guia, consulte a seguinte documentação da API:

Voltar

Mapeamento de classe