Configuring mapping between Database Table(s) and Data Model Class(es) using DataAnnotation

Description Article
Table of Contents
Summary

Entity Framework Code First provides a set of annotation attributes, which can be applied on the domain classes and properties.

Description

DataAnnotation attributes are defined on System.ComponentModel.DataAnnotations and System.ComponentModel.DataAnnotations.Schema namespaces:

  • The first affects the configuration of a column.
  • The second impacts schema of the database.

 

System.ComponentModel.DataAnnotations Attributes:

Attribute Description Applicable On Overrided Code First Conventions Comments
Table Specifies name of the database table which will be mapped with the class Class Creates a table name same as class name Schema – indicates the database schema to use
Column Specifies column name and data type which will be mapped with the property Property Creates a column name same as property name. Order (optional) – Indicates the order of the column in the table definition;
TypeName – Indicates the correspondent database type
Index Create an Index for specified column. (EF 6.1 onwards only) Property By default, Index name will be IX_{property name} Name (optional)- Name of the index
IsClustered (optional)- Indicates if this is a CLUSTERED type index;
IsUnique (optional)- Indicates if this is a UNIQUE type index
ForeignKey Indicates the property used as a foreign key in a relationship, when foreign key property(s) are exposed in the object model:- On bidirectionalrelationships specifies the name of the associated foreign key property/properties when added to a Navigation property (in the same class), or specifies the name of the associated navigation property when added to a foreign key property (in the same class).- On unidirectional relationships the attribute is added to navigation property with the information of the name of the foreign key property in the related class Navigation Property, Property / Relationship Attribute Expects foreign key property name match with primary key property in the related class Name (optional) – Name of the foreign key
NotMapped Specifies that property will not be mapped with database Property Code First also does not create a column for a properties which does not have either getters or setters
DatabaseGenerated Specifies that property will be mapped to Computed column of the database table. So the property will be read-only property Property It can be used to map the property to database IDENTITY column (auto incremental column)
InverseProperty Used when multiple relationships exists between two classes. Specifies which reference property of parent class the property in the related class refers to Navigation Property / Relationship Attribute Code First creates {CLASS NAME}_{PRIMARY KEY} FK column if a foreign key property was not included in a parent classNote: If not used the mapping conventions would not detect which ends of these relationships belong together and will duplicate relationships (reflected in the number of foreign keys in the table) than actually exists The InversePropertyattribute is only necessary on one end of the relationship, therefore can be omitted on the other endNote: To indicate a different name for the FK in the database, the ForeignKey attribute can be used in the foreign key property of the related class
ComplexType Mark the class as complex type in EF. Property

System.ComponentModel.DataAnnotations.Schema Attributes:

Attribute Description Applicable On Overrided Code First Conventions Comments
Key Mark property as EntityKey which will be mapped to PK of related table. Property Creates a primary key column for a property whose name is “Id” or {CLASSNAME} + “Id” A composite PK can be identified using multiple Key attributes in conjuntion with the Column attribute and the “Order” parameter)
TimeStamp Mark the property as a non-nullable timestamp column in the database Property Can be applied to only one byte array property of a domain classNote: Code First automatically use this TimeStamp column in concurrency check
ConcurrencyCheck ConcurrencyCheck annotation allows you to flag one or more properties to be used for concurrency checking in the database when a user edits or deletes an entity. Property
Required The Required annotation will force EF (and MVC) to ensure that property has data in it Navigation property, Property Code First will create a NOT NULL column in a database table
MinLength MinLength annotation validates property whether it has minimum length of array or string. Property Can be applied to a string or array type property of a domain class
MaxLength MaxLength annotation maximum length of property which in turn sets the maximum length of column in the database Property
StringLength Specifies the minimum and maximum length of characters that are allowed in a data field. Property

 

Note

DataAnnotations attributes overrides default Code First conventions.

Note

DataAnnotations are a subset of configuration options. Fluent API provides full set of configuration options available in Code First, and therefore may be required.

Inverse Property

When InverseProperty attribute was not used:

When InverseProperty attribute was used:

Operations
Domain classes samples configured using DataAnnotation attributes
How to do it
using System.ComponentModel.DataAnnotations.Schema;

namespace EF.Demo
{
    [Table("Student", Schema="Training")]
    public class Student
    {
        public Student()
        { 

        }

        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        [Column(Order=1)]
        public int StudentID { get; set; }

        [Key]
        [Column(Order=2)]
        public int StudentNumber { get; set; }

	[Column("Name", Order=1, TypeName="varchar")]
        [MaxLength(50),MinLength(2)]
        [Required]
        public string StudentName { get; set; }

	[Index]
        public int RegistrationNumber { get; set; }

        public int CurrentStandardId { get; set; }
        public int PreviousStandardId { get; set; }

        [ForeignKey("CurrentStandardId")]
        public Standard CurrentStandard { get; set; }

        [ForeignKey("PreviousStandardId")]
        public Standard PreviousStandard { get; set; }

	[NotMapped]
        public int Age { get; set; }

        [TimeStamp]
        public byte[] RowVersion { get; set; }

        public ExtraInformation Info { get; set; }
    }

    public class Standard
    {
        public Standard()
        { 

        }

        public int StandardId { get; set; }

        public string StandardName { get; set; }

        [InverseProperty("CurrentStandard")]
        public ICollection<Student> CurrentStudents { get; set; }

        [InverseProperty("PreviousStandard")]
        public ICollection<Student> PreviousStudents { get; set; }

    }

    [ComplexType]
    public class Address
    {
        public string Location { get; set; }
        public string City { get; set; }
        public string Country { get; set; }
    }

    public class ExtraInformation
    {
      public string Info1 { get; set; }
      public string Info2 { get; set; }
      public string Info3 { get; set; }
    } 

  public class Instructor
  {
    public Instructor()
    {
    } 

    // Primary key
    public int InstructorID { get; set; }
    public string LastName { get; set; }
    public string FirstName { get; set; }
    public System.DateTime HireDate { get; set; }
  } 

  public class OfficeAssignment
  {
    // Specifying InstructorID as a primary
    [Key]
    public Int32 InstructorID { get; set; } 

    public string Location { get; set; } 

    // Navigation property
    public virtual Instructor Instructor { get; set; }
  }
}
References

[1] Refer to this article for further information on DataAnnotation attributes on Code First