Overriding code-first convention using Data Annotations

by Sachin Singh


Posted on Thursday, 21 January 2021

Tags: Overriding code-first convention using Data Annotations

Table Name

By Default table names are plural of your class name, if you want to override this convention then you can use [Table] attribute on your class , which accepts two parameters as table name and additionally schema name if your table is in other schema than dbo


 [Table("tbl_Employee", schema="Organization")]
 public Class Employee
 {
  // class definition
 }

Column Names

By default column names are property names , if you want to override this convention then you can use [Column] attribute which accepts column name and additionally Data type name as shown below


  public Class Employee
  {
  [Column("Emp_Name", TypeName="varchar")]
   public string Name {get;set;}
  }

Primary Key

By default the property named as Id or {ClassName}Id is considered as primary key , but sometimes you may want to make other column which neither ends with the word Id nor named as Id , then you can use [Key] attribute .


 Public Class Product
 {
  [Key]
  public string ISBN {get;set;}
 }

By default primary keys are considered as Identity if you want to override this convention you can use [DatabaseGerated] attribute which accepts an enum i.e. DatabaseGeneratedOption which have 3 values as None, Identity or computed.


 public class Product
  {
  [Key] [DatabaseGenerated(DatabaseGeneratedOption.None)]
   public string ISBN {get;set;}
   }

Composite Keys

To specify composite keys you can use [Key] attribute along with [Column] attribute by specifying column-order as shown in below code.


  public class Product
  {
  [Key] 
  [Column(order=1)]
  public int OrderId {get;set;}
  [Key] 
  [Column(order=2)]
  public int OrderItemId {get;set;}
  }

Nulls

A column is nullable if property is nullable , to make a column not nullable , you can use [Required] attribute.


  public class Employee
  {
  [Required]
  public string Name {get;set;}
  }

Column Length

To specify the column length you can use [MaxLength] attribute on properties.


  public class Employee
  {
  [MaxLength(50)]
  public string Name {get;set;}
  }

Indices

To specify index on a column you can use Index attribute on property.


  public class Employee
  {
  [Index(IsUnique=true)]
   public string Name {get;set;}
  }

To specify composite indices you need to additionally provide ordering.


 public class Author
 {
 [Index(“IX_AuthorStudentsCount”,1)]
 public int AuthorId { get; set;}
 [Index(“IX_AuthorStudentsCount”,2)]
 public int StudentsCount { get; set;}
 }

Foreign Keys

The default convention is ,If the Name of a property of an Entity matches with the name of primary key property of another Entity , then Entity Framework makes the property a Navigation property and the corresponding column a foreign key in the database table.


 using System.ComponentModel.DataAnnotations.Schema;
  public class Employee
  {
    public int EmployeeID { get; set; }
    public string EmployeeName { get; set; }     
    //Foreign key for Department
    public int DepartmentId { get; set; }
    public Department Department { get; set; }
  }

 public class Department
 {
    public int DepartmentId { get; set; }
    public string DepartmentName { get; set; }   
    public ICollection <Employee > Employees { get; set; }
 }

As you can see , in the above example a property name DepartmentId in Employee entity matches with the primary key property of Department entity, so DepartmentId..This will automatically create a navigation property in Employee Entity and Foreign Key column in Database table.

To override this default convention , you can use ForeignKey attribute . The [ForeignKey] attribute overrides the default convention for a foreign key and allows us to specify the foreign key property in the dependent entity whose name does not match with the primary key property of the principal or primary entity.

There are three ways to apply the [ForeignKey(name)] attribute :
  1. [ForeignKey(NavigationPropertyName)] on the foreign key property in the dependent entity
  2. [ForeignKey(ForeignKeyPropertyName)] on the navigation property in the dependent entity
  3. [ForeignKey(ForeignKeyPropertyName)] on the navigation property in the principal entity

[ForeignKey] on the foreign key property in the dependent entity

The [ForeignKey]attribute on the foreign key property in the dependent entity can be specified as a parameter as shown below.


 using System.ComponentModel.DataAnnotations.Schema;
  public class Employee
  {
    public int EmployeeID { get; set; }
    public string EmployeeName { get; set; }     
    [ForeignKey("Department")]
    public int DepartmentId { get; set; }
    public Department Department { get; set; }
  }

 public class Department
 {
    public int DepartmentId { get; set; }
    public string DepartmentName { get; set; }
    
    public ICollection <Employee> Employees { get; set; }
 }

In the above example, the [ForeignKey] attribute is applied on the DepartmentId and specified in the name of the navigation property Department. This will create the foreign key column named DepartmentId in the Employees table, preventing the generation of a DepartmentId column in the database.

[ForeignKey] on the navigation property in the dependent entity

The [ForeignKey] attribute can be applied to the navigation property in dependent Entity, as shown below.


 using System.ComponentModel.DataAnnotations.Schema;
 public class Employee
  {
    public int EmployeeID { get; set; }
    public string EmployeeName { get; set; }       
    public int DepartmentId { get; set; }    
    [ForeignKey("DepartmentId")]
    public Department Department { get; set; }
  }

  public class Department
  {
    public int DepartmentId { get; set; }
    public string DepartmentName { get; set; }    
    public ICollection <Employee> Employees { get; set; }
  }

In the above example, the [ForeignKey] attribute is applied on the Department navigation property and the name of the foreign key property DepartmentId is specified. This will create the foreign key column named DepartmentId in the Employees table, preventing the generation of a DepartmentId column in the database.

[ForeignKey] on the navigation property in the principal entity

The [ForeignKey] attribute can be applied to the navigation property in the principal entity, as shown below.


  using System.ComponentModel.DataAnnotations.Schema;
  public class Employee
   {
    public int EmployeeID { get; set; }
    public string EmployeeName { get; set; }      
    public int DepartmentId { get; set; }
    public Department Department { get; set; }
  }

  public class Department
  {
    public int DepartmentId { get; set; }
    public string DepartmentName { get; set; }   
    [ForeignKey("DepartmentId")]
    public ICollection <Employee> Employees { get; set; }
  }

In the above example, the [ForeignKey] attribute is applied on the Employees navigation property in the principal entity Department. This will create a foreign key column DepartmentId in the Employees table in the database.