entity-framework-data-annotations

Data Annotations en Entity Framework

  • 5 min

Las Data Annotations son un conjunto de atributos predefinidos que se utilizan en C# para aplicar configuraciones específicas a las propiedades de las clases.

Estos atributos ayudan a configurar cómo deben ser tratadas las entidades y propiedades de nuestro modelo, al ser mapeadas a las tablas y columnas de la base de datos.

Por ejemplo, nos permiten definir propiedades como claves primarias, campos requeridos, longitudes máximas de texto, y más.

Como cualquier otro atributo, para aplicarlo simplemente tendremos que ponerlo delante de la clase o propiedad que queramos modificar.

Están disponibles en System.ComponentModel.DataAnnotations, por lo que tendréis que añadir el namespace.

Principales Data Annotations

Vamos a ver algunas de las Data Annotation más importantes de Entity Framework, y cómo usar cada una de ellas.

Configuración de tablas y columnas

El atributo [Table] especifica el nombre de la tabla asociada con una entidad

[Table("Productos")]  
public class Product  
{  
    public int Id { get; set; }  
    public string Name { get; set; }  
}  

El atributo [Column] permite especificar el nombre de la columna en la base de datos que corresponde a una propiedad.

public class Student
{
    public int StudentId { get; set; }

    [Column("Full_Name")] // Mapea la propiedad "Name" a la columna "Full_Name"
    public string Name { get; set; }
}

El atributo [DataType] permite especificar el tipo de datos de una propiedad.

public class Student
{
    public int StudentId { get; set; }

    [DataType(DataType.EmailAddress)] // Especifica que esta propiedad debe ser una dirección de correo electrónico
    public string Email { get; set; }
}

Configuración de claves

El atributo [Key] se utiliza para marcar una propiedad como clave primaria de la entidad.

public class Student
{
    [Key] // Marca esta propiedad como clave primaria
    public int StudentId { get; set; }

    public string Name { get; set; }
}

El atributo [DatabaseGenerated] controla cómo se generan los valores de una propiedad en la base de datos. Es especialmente útil para campos autoincrementales, valores calculados o fechas generadas automáticamente.

public class Product
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]  
    public int Id { get; set; } // Se genera automáticamente al insertar (IDENTITY)

    [DatabaseGenerated(DatabaseGeneratedOption.Computed)]  
    public DateTime LastUpdated { get; set; } // Lo calcula la base de datos (ej: GETDATE())

    [DatabaseGenerated(DatabaseGeneratedOption.None)]  
    public string ProductCode { get; set; } // No se genera automáticamente (valor manual)
}

Validación y restricciones

El atributo [Required] se utiliza para indicar que una propiedad no puede ser nula en la base de datos. Es similar a la restricción NOT NULL en SQL.

public class Student
{
    public int StudentId { get; set; }

    [Required] // Indica que el nombre es obligatorio
    public string Name { get; set; }
}

El atributo [MaxLength] permiten establecer un límite para la longitud de una cadena de texto.

public class Product  
{  
    [MaxLength(100)]  
    public string Name { get; set; } // NVARCHAR(100)  
}  

Si intentas guardar una cadena de texto que exceda los 100 caracteres, EF Core rechazará la operación.

El atributo [StringLength] define una longitud máxima y opcionalmente una mínima,

[StringLength(50, MinimumLength = 3)]  
public string ShortDescription { get; set; }  

El atributo [Range] se utiliza para especificar un rango de valores válidos para una propiedad numérica.

public class Course
{
    public int CourseId { get; set; }

    [Range(1, 10)] // El rango de valores permitidos para el número de créditos
    public int Credits { get; set; }
}

Configuración de relaciones

El atributo [ForeignKey] se utiliza para establecer una relación entre dos entidades. En este caso, se puede usar para especificar que una propiedad es una clave foránea que se refiere a otra entidad.

public class Enrollment
{
    public int EnrollmentId { get; set; }

    [ForeignKey("Student")] // Establece la relación con la entidad Student
    public int StudentId { get; set; }
    
    public Student Student { get; set; }  // Propiedad de navegación
}

Este atributo permite que EF Core sepa que StudentId es una clave foránea que hace referencia a la tabla Student.

El atributo [InverseProperty] se utiliza para especificar la propiedad de navegación inversa en una relación entre dos entidades.

Esto es útil cuando hay múltiples relaciones entre las mismas entidades y EF Core necesita ayuda para determinar cómo se relacionan.

public class Student
{
    public int StudentId { get; set; }
    public string Name { get; set; }

    [InverseProperty("Student")] // Establece la propiedad de navegación inversa
    public ICollection<Enrollment> Enrollments { get; set; }
}

Este atributo le indica a EF Core que la propiedad Enrollments en Student es la inversa de la propiedad Student en Enrollment, evitando ambigüedades en el mapeo de relaciones.

Ejemplo completo

Vamos a verlo con un ejemplo completo, de cómo podría ser el modelo de datos de un blog muy simple, que solo tuviera Author y Posts.

[Table("BlogPosts")]  
public class Post  
{  
    [Key]  
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]  
    public int PostId { get; set; }  

    [Required]  
    [MaxLength(200)]  
    public string Title { get; set; }  

    [Column("Contenido", TypeName = "nvarchar(max)")]  
    public string Content { get; set; }  

    [ForeignKey("Author")]  
    public int AuthorId { get; set; }  

    public Author Author { get; set; }  

    public ICollection<Comment> Comments { get; set; }  
}  

[Table("Autores")]  
public class Author  
{  
    public int Id { get; set; }  

    [Required]  
    [StringLength(100)]  
    public string Name { get; set; }  

    [InverseProperty("Author")]  
    public ICollection<Post> Posts { get; set; }  
}  

Aquí se ve muy bien los puntos fuertes y débiles de las Data Annotations. Es sencillo y cómodo, pero “ensucia” mucho nuestros objetos