entity-framework-data-annotations

Data Annotations in Entity Framework

  • 5 min

Data Annotations are a set of predefined attributes used in C# to apply specific configurations to the properties of classes.

These attributes help configure how entities and properties in our model should be treated when mapped to the tables and columns of the database.

For example, they allow us to define properties as primary keys, required fields, maximum text lengths, and more.

Like any other attribute, to apply it we simply have to place it in front of the class or property we want to modify.

They are available in System.ComponentModel.DataAnnotations, so you will need to add the namespace.

Main Data Annotations

Let’s look at some of the most important Data Annotations in Entity Framework and how to use each of them.

Table and Column Configuration

The [Table] attribute specifies the name of the table associated with an entity.

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

The [Column] attribute allows specifying the name of the database column that corresponds to a property.

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

    [Column("Full_Name")] // Maps the property "Name" to the column "Full_Name"
    public string Name { get; set; }
}

The [DataType] attribute allows specifying the data type of a property.

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

    [DataType(DataType.EmailAddress)] // Specifies that this property should be an email address
    public string Email { get; set; }
}

Key Configuration

The [Key] attribute is used to mark a property as the primary key of the entity.

public class Student
{
    [Key] // Marks this property as the primary key
    public int StudentId { get; set; }

    public string Name { get; set; }
}

The [DatabaseGenerated] attribute controls how values of a property are generated in the database. It is especially useful for auto-increment fields, calculated values, or automatically generated dates.

public class Product
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]  
    public int Id { get; set; } // Automatically generated upon insertion (IDENTITY)

    [DatabaseGenerated(DatabaseGeneratedOption.Computed)]  
    public DateTime LastUpdated { get; set; } // Calculated by the database (e.g., GETDATE())

    [DatabaseGenerated(DatabaseGeneratedOption.None)]  
    public string ProductCode { get; set; } // Not automatically generated (manual value)
}

Validation and Constraints

The [Required] attribute is used to indicate that a property cannot be null in the database. It is similar to the NOT NULL constraint in SQL.

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

    [Required] // Indicates that the name is required
    public string Name { get; set; }
}

The [MaxLength] attribute allows setting a limit for the length of a string.

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

If you try to save a string that exceeds 100 characters, EF Core will reject the operation.

The [StringLength] attribute defines a maximum length and optionally a minimum one.

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

The [Range] attribute is used to specify a range of valid values for a numeric property.

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

    [Range(1, 10)] // The range of allowed values for the number of credits
    public int Credits { get; set; }
}

Relationship Configuration

The [ForeignKey] attribute is used to establish a relationship between two entities. In this case, it can be used to specify that a property is a foreign key referring to another entity.

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

    [ForeignKey("Student")] // Establishes the relationship with the Student entity
    public int StudentId { get; set; }
    
    public Student Student { get; set; }  // Navigation property
}

This attribute allows EF Core to know that StudentId is a foreign key referencing the Student table.

The [InverseProperty] attribute is used to specify the inverse navigation property in a relationship between two entities.

This is useful when there are multiple relationships between the same entities, and EF Core needs help determining how they relate.

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

    [InverseProperty("Student")] // Establishes the inverse navigation property
    public ICollection<Enrollment> Enrollments { get; set; }
}

This attribute tells EF Core that the Enrollments property in Student is the inverse of the Student property in Enrollment, avoiding ambiguities in relationship mapping.

Complete Example

Let’s look at it with a complete example of what the data model for a very simple blog could look like, one that only had Author and Posts.

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

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

    [Column("Content", 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("Authors")]  
public class Author  
{  
    public int Id { get; set; }  

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

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

Here we can clearly see the strengths and weaknesses of Data Annotations. It’s simple and convenient, but it “clutters” our objects a lot.