Propriedades da Entidade

Cada tipo de entidade em seu modelo tem um conjunto de propriedades, que o EF Core lerá e gravará no banco de dados. Se você estiver usando um banco de dados relacional, as propriedades da entidade serão mapeadas para colunas de tabela.

Propriedades incluídas e excluídas

Por convenção, todas as propriedades públicas com um getter e um setter serão incluídas no modelo.

Propriedades específicas podem ser excluídas da seguinte maneira:

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }

    [NotMapped]
    public DateTime LoadedFromDatabase { get; set; }
}

Nomes de Colunas

Por convenção, ao usar um banco de dados relacional, as propriedades da entidade são mapeadas para colunas de tabela com o mesmo nome da propriedade.

Se preferir configurar suas colunas com nomes diferentes, você poderá fazer isso como o seguinte snippet de código:

public class Blog
{
    [Column("blog_id")]
    public int BlogId { get; set; }

    public string Url { get; set; }
}

Tipos de dados de coluna

Ao usar um banco de dados relacional, o provedor de banco de dados seleciona um tipo de dados com base no tipo .NET da propriedade. Ele também leva em conta outros metadados, como o comprimento máximo configurado, se a propriedade faz parte de uma chave primária, etc.

Por exemplo, o SQL Server mapeia propriedades DateTime para colunas datetime2(7), e propriedades string para colunas nvarchar(max) (ou para propriedades nvarchar(450) usadas como chave).

Você também pode configurar suas colunas para especificar um tipo de dados exato para uma coluna. Por exemplo, o código a seguir configura Url como uma cadeia de caracteres não unicode com comprimento máximo de 200, e Rating como decimal com precisão 5 e escala de 2:

public class Blog
{
    public int BlogId { get; set; }

    [Column(TypeName = "varchar(200)")]
    public string Url { get; set; }

    [Column(TypeName = "decimal(5, 2)")]
    public decimal Rating { get; set; }
}

Comprimento máximo

Configurar um comprimento máximo fornece uma dica para o provedor de banco de dados sobre o tipo de dados de coluna apropriado a ser escolhido para uma determinada propriedade. O comprimento máximo só se aplica a tipos de dados de matriz, como string e byte[].

Observação

O Entity Framework não faz nenhuma validação de comprimento máximo antes de passar dados para o provedor. Cabe ao provedor ou ao repositório de dados validar se apropriado. Por exemplo, ao direcionar o SQL Server, exceder o comprimento máximo resultará em uma exceção, pois o tipo de dados da coluna subjacente não permitirá que dados em excesso sejam armazenados.

No exemplo a seguir, configurar um comprimento máximo de 500 fará com que uma coluna de tipo nvarchar(500) seja criada no SQL Server:

public class Blog
{
    public int BlogId { get; set; }

    [MaxLength(500)]
    public string Url { get; set; }
}

Precisão e escala

Alguns tipos de dados relacionais dão suporte às facetas de precisão e escala; eles controlam quais valores podem ser armazenados e quanto armazenamento é necessário para a coluna. Quais tipos de dados dão suporte à precisão e à escala dependem do banco de dados, mas na maioria dos bancos de dados os tipos decimal e DateTime dão suporte a essas facetas. Para propriedades decimal, a precisão define o número máximo de dígitos necessários para expressar qualquer valor que a coluna conterá e a escala define o número máximo de casas decimais necessárias. Para propriedades DateTime, a precisão define o número máximo de dígitos necessários para expressar frações de segundos e a escala não é usada.

Observação

O Entity Framework não faz nenhuma validação de precisão ou escala antes de passar dados para o provedor. Cabe ao provedor ou ao armazenamento de dados validar conforme apropriado. Por exemplo, ao direcionar o SQL Server, uma coluna de tipo de dados datetime não permite que a precisão seja definida, enquanto uma datetime2 pode ter precisão entre 0 e 7, inclusive.

No exemplo a seguir, configurar a propriedade Score para ter precisão 14 e escala 2 fará com que uma coluna do tipo decimal(14,2) seja criada no SQL Server e configurar a LastUpdated propriedade para ter precisão 3 causará uma coluna do tipo datetime2(3):

public class Blog
{
    public int BlogId { get; set; }
    [Precision(14, 2)]
    public decimal Score { get; set; }
    [Precision(3)]
    public DateTime LastUpdated { get; set; }
}

A escala nunca é definida sem definir primeiro a precisão, portanto, a Anotação de Dados para definir a escala é [Precision(precision, scale)].

Unicode

Em alguns bancos de dados relacionais, existem tipos diferentes para representar dados de texto Unicode e não Unicode. Por exemplo, no SQL Server, nvarchar(x) é usado para representar dados Unicode no UTF-16, enquanto varchar(x) é usado para representar dados não Unicode (mas confira as anotações sobre o suporte do SQL Server UTF-8). Para bancos de dados que não dão suporte a esse conceito, configurar isso não tem efeito.

As propriedades de texto são configuradas como Unicode por padrão. Você pode configurar uma coluna como não Unicode da seguinte maneira:

public class Book
{
    public int Id { get; set; }
    public string Title { get; set; }

    [Unicode(false)]
    [MaxLength(22)]
    public string Isbn { get; set; }
}

Propriedades obrigatórias e opcionais

Uma propriedade será considerada opcional se for válido que ela contenha null. Se null não for um valor válido a ser atribuído a uma propriedade, essa propriedade será considerada necessária. Ao mapear para um esquema de banco de dados relacional, as propriedades necessárias são criadas como colunas não anuláveis e as propriedades opcionais são criadas como colunas anuláveis.

Convenções

Por convenção, uma propriedade cujo tipo .NET pode conter nulo será configurada como opcional, enquanto as propriedades cujo tipo .NET não pode conter nulo serão configuradas como necessárias. Por exemplo, todas as propriedades com tipos de valor .NET (int, decimal, bool, etc.) são configuradas como necessárias e todas as propriedades com tipos de valor .NET anuláveis (int?, decimal?, bool?, etc.) são configuradas como opcionais.

O C# 8 introduziu um novo recurso chamado tipos de referência anuláveis (NRT), que permite que os tipos de referência sejam anotados indicando se é válido que eles contenham nulo ou não. Esse recurso é habilitado por padrão em novos modelos de projeto, mas permanece desabilitado em projetos existentes, a menos que seu uso seja explicitamente aceito. Tipos de referência anuláveis afetam o comportamento do EF Core da seguinte maneira:

  • Se os tipos de referência anuláveis estiverem desabilitados, todas as propriedades com tipos de referência do .NET serão configuradas como opcionais por convenção (por exemplo, string).
  • Se os tipos de referência anuláveis estiverem habilitados, as propriedades serão configuradas com base na nulidade C# de seu tipo .NET: string? será configurada como opcional, mas string será configurada como necessária.

O exemplo a seguir mostra um tipo de entidade com propriedades obrigatórias e opcionais, com o recurso de referência anulável desabilitado e habilitado:

public class CustomerWithoutNullableReferenceTypes
{
    public int Id { get; set; }

    [Required] // Data annotations needed to configure as required
    public string FirstName { get; set; }

    [Required] // Data annotations needed to configure as required
    public string LastName { get; set; }

    public string MiddleName { get; set; } // Optional by convention
}

O uso de tipos de referência anuláveis é recomendado, pois flui a nulidade expressa no código C# para o modelo do EF Core e para o banco de dados e evita o uso da API fluente ou anotações de dados para expressar o mesmo conceito duas vezes.

Observação

Tenha cuidado ao habilitar tipos de referência anuláveis em um projeto existente: as propriedades de tipo de referência que foram configuradas anteriormente como opcionais agora serão configuradas conforme necessário, a menos que sejam explicitamente anotadas como anuláveis. Ao gerenciar um esquema de banco de dados relacional, isso pode fazer com que sejam geradas migrações, alterando a nulidade da coluna de banco de dados.

Para obter mais informações sobre tipos de referência que permitem valor nulo e como usá-los com o EF Core, confira a página de documentação dedicada para esse recurso.

Configuração explícita

Uma propriedade que seria opcional por convenção pode ser configurada como necessária da seguinte maneira:

public class Blog
{
    public int BlogId { get; set; }

    [Required]
    public string Url { get; set; }
}

Ordenações de coluna

Uma ordenação pode ser definida em colunas de texto, determinando como elas são comparadas e ordenadas. Por exemplo, o snippet de código a seguir configura uma coluna do SQL Server para não diferenciar maiúsculas de minúsculas:

modelBuilder.Entity<Customer>().Property(c => c.Name)
    .UseCollation("SQL_Latin1_General_CP1_CI_AS");

Se todas as colunas em um banco de dados precisarem usar uma determinada ordenação, defina a ordenação no nível do banco de dados.

Informações gerais sobre o suporte do EF Core para ordenações podem ser encontradas na página de documentação de ordenação.

Comentários de coluna

Você pode definir um comentário de texto arbitrário que é definido na coluna de banco de dados, permitindo que você documente seu esquema no banco de dados:

public class Blog
{
    public int BlogId { get; set; }

    [Comment("The URL of the blog")]
    public string Url { get; set; }
}

Ordem das colunas

Por padrão, ao criar uma tabela com Migrações, o EF Core ordena primeiro as colunas de chave primária, seguidas por propriedades do tipo de entidade e tipos de propriedade e, por fim, propriedades de tipos base. No entanto, você pode especificar uma ordem diferente para as colunas:

public class EntityBase
{
    [Column(Order = 0)]
    public int Id { get; set; }
}

public class PersonBase : EntityBase
{
    [Column(Order = 1)]
    public string FirstName { get; set; }

    [Column(Order = 2)]
    public string LastName { get; set; }
}

public class Employee : PersonBase
{
    public string Department { get; set; }
    public decimal AnnualSalary { get; set; }
}

A API Fluente pode ser usada para substituir a ordenação feita com atributos, incluindo a resolução de conflitos quando atributos em propriedades diferentes especificam o mesmo número de ordem.

Observe que, de modo geral, a maioria dos bancos de dados só dá suporte a colunas de ordenação quando a tabela é criada. Isso significa que o atributo de ordem de coluna não pode ser usado para ordenar novamente as colunas de uma tabela existente.