Propiedades de entidad

Cada tipo de entidad del modelo tiene un conjunto de propiedades, que EF Core leerá y escribirá a partir de la base de datos. Si usa una base de datos relacional, las propiedades de entidad se asignan a columnas de tabla.

Propiedades incluidas y excluidas

Por convención, todas las propiedades públicas con un captador y un establecedor se incluirán en el modelo.

Las propiedades específicas se pueden excluir de la siguiente manera:

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

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

Nombre de columna

Por convención, cuando se usa una base de datos relacional, las propiedades de entidad se asignan a columnas de tabla que tienen el mismo nombre que la propiedad.

Si prefiere configurar las columnas con nombres diferentes, puede hacerlo como el siguiente fragmento de código:

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

    public string Url { get; set; }
}

Tipos de datos de columna

Cuando se usa una base de datos relacional, el proveedor de bases de datos selecciona un tipo de datos basado en el tipo .NET de la propiedad. También tiene en cuenta otros metadatos, como la longitud máxima configurada, si la propiedad forma parte de una clave principal, etc.

Por ejemplo, SQL Server asigna DateTime propiedades a datetime2(7) columnas y string propiedades a nvarchar(max) columnas (o a nvarchar(450) en el caso de las propiedades que se usan como clave).

También puede configurar las columnas para especificar un tipo de datos exacto para una columna. Por ejemplo, el código siguiente configura Url como una cadena no unicode con la longitud máxima de 200 y Rating como decimal con precisión de 5 y 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; }
}

Largo máximo

La configuración de una longitud máxima proporciona una sugerencia al proveedor de base de datos sobre el tipo de datos de columna adecuado para elegir una propiedad determinada. La longitud máxima solo se aplica a los tipos de datos de matriz, como string y byte[].

Nota:

Entity Framework no realiza ninguna validación de longitud máxima antes de pasar datos al proveedor. Es necesario que el proveedor o el almacén de datos se validen si procede. Por ejemplo, al dirigirse a SQL Server, si se supera la longitud máxima, se producirá una excepción, ya que el tipo de datos de la columna subyacente no permitirá almacenar datos excesivos.

En el ejemplo siguiente, configurar una longitud máxima de 500 hará que se cree una columna de tipo nvarchar(500) en SQL Server:

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

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

Precisión y escala

Algunos tipos de datos relacionales admiten las facetas de precisión y escala; estos controlan qué valores se pueden almacenar y cuánto almacenamiento se necesita para la columna. Los tipos de datos que admiten la precisión y la escala dependen de la base de datos, pero en la mayoría de las bases de datos, los tipos decimal y DateTime no admiten estas facetas. Para las propiedades decimal, la precisión define el número máximo de dígitos necesarios para expresar cualquier valor que contendrá la columna y la escala define el número máximo de posiciones decimales necesarias. Para las propiedades DateTime, la precisión define el número máximo de dígitos necesarios para expresar fracciones de segundos y no se usa la escala.

Nota:

Entity Framework no realiza ninguna validación de la precisión o escala antes de pasar datos al proveedor. Es necesario que el proveedor o el almacén de datos se validen si procede. Por ejemplo, cuando el destino es SQL Server, una columna de tipo de datos datetime no permite establecer la precisión, mientras que una datetime2 puede tener una precisión entre 0 y 7 inclusive.

En el ejemplo siguiente, configurar la propiedad Score para tener una precisión de 14 y una escala de 2 hará que se cree una columna de tipo decimal(14,2) en SQL Server y configurar la propiedad LastUpdated para tener una precisión de 3 provocará una columna de 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; }
}

La escala nunca se define sin definir primero la precisión, por lo que la anotación de datos para definir la escala es [Precision(precision, scale)].

Unicode

En algunas bases de datos relacionales, existen diferentes tipos para representar datos de texto Unicode y no Unicode. Por ejemplo, en SQL Server, se usa nvarchar(x) para representar datos Unicode en UTF-16, mientras que varchar(x) se usa para representar datos no Unicode (pero consulte las notas sobre compatibilidad con UTF-8 de SQL Server). En el caso de las bases de datos que no admiten este concepto, la configuración no tiene ningún efecto.

Las propiedades de texto se configuran como Unicode de forma predeterminada. Puede configurar una columna como no Unicode como sigue:

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

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

Propiedades obligatorias y opcionales

Una propiedad se considera opcional si es válida para que contenga null. Si null no es un valor válido que se va a asignar a una propiedad, se considera una propiedad necesaria. Al asignar a un esquema de base de datos relacional, las propiedades necesarias se crean como columnas que no aceptan valores NULL y las propiedades opcionales se crean como columnas que aceptan valores NULL.

Convenciones

Por convención, una propiedad cuyo tipo de .NET puede contener null se configurará como opcional, mientras que las propiedades cuyo tipo de .NET no puede contener null se configurarán según sea necesario. Por ejemplo, todas las propiedades con tipos de valor de .NET (int, decimal, bool, etc.) se configuran según sea necesario y todas las propiedades con tipos de valor .NET que aceptan valores NULL (int?, decimal?, bool?, etc.) se configuran como opcionales.

C# 8 ha introducido una nueva característica denominada tipos de referencia nula (NRT), lo que permite anotar los tipos de referencia al indicar si es válido para que contengan null o no. Esta característica está habilitada de forma predeterminada en las nuevas plantillas de proyecto, pero permanece deshabilitada en los proyectos existentes a menos que se escoja explícitamente. Los tipos de referencia que aceptan valores NULL afectan al comportamiento de EF Core de la siguiente manera:

  • Si los tipos de referencia que aceptan valores NULL están deshabilitados, todas las propiedades con tipos de referencia de .NET se configuran como opcionales por convención (por ejemplo, string).
  • Si los tipos de referencia que aceptan valores NULL están habilitados, las propiedades se configurarán en función de la nulabilidad de C# de su tipo de .NET: string? se configurará como opcional, pero string se configurará según sea necesario.

En el ejemplo siguiente se muestra un tipo de entidad con propiedades obligatorias y opcionales, con la característica de referencia que acepta valores NULL deshabilitada y habilitada:

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
}

Se recomienda usar tipos de referencia que aceptan valores NULL, ya que fluye la nulabilidad expresada en código de C# al modelo de EF Core y a la base de datos, y obvia el uso de la API de Fluent o anotaciones de datos para expresar el mismo concepto dos veces.

Nota:

Tenga cuidado al habilitar los tipos de referencia que aceptan valores NULL en un proyecto existente: las propiedades de tipo de referencia que se configuraron previamente como opcionales ahora se configurarán según sea necesario, a menos que se anoten explícitamente para que admitan un valor NULL. Al administrar un esquema de base de datos relacional, esto puede provocar que se generen migraciones que modifiquen la nulabilidad de la columna de base de datos.

Para obtener más información sobre los tipos de referencia que aceptan valores NULL y cómo usarlos con EF Core, consulte la página de documentación dedicada de esta característica.

Configuración explícita

Una propiedad que sería opcional por convención se puede configurar para que sea necesaria de la siguiente manera:

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

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

Intercalaciones de columna

Se puede definir una intercalación en columnas de texto, lo que determina cómo se comparan y ordenan. Por ejemplo, el siguiente fragmento de código configura una columna de SQL Server que no distingue mayúsculas de minúsculas:

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

Si todas las columnas de una base de datos necesitan usar una determinada intercalación, pruebe a definir la intercalación en el nivel de base de datos.

Puede encontrar información general sobre la compatibilidad de EF Core con intercalaciones en la página de documentación de intercalación.

Comentarios de columna

Puede establecer un comentario de texto arbitrario que se establece en la tabla de base de datos, lo que le permite documentar el esquema en la base de datos:

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

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

Orden de columnas

De forma predeterminada, al crear una tabla con Migraciones, EF Core primero ordena las columnas de clave principal, luego las propiedades del tipo de entidad y los tipos de propiedad y, por último, las propiedades de los tipos base. Sin embargo, puede especificar un orden de columna diferente:

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

La API de Fluent se puede usar para reemplazar la ordenación realizada con atributos, incluida la resolución de conflictos cuando los atributos de propiedades diferentes especifican el mismo número de orden.

Tenga en cuenta que, en el caso general, la mayoría de las bases de datos solo admiten la ordenación de columnas cuando se crea la tabla. Esto significa que el atributo de orden de columna no se puede usar para volver a ordenar las columnas de una tabla existente.