Code First Conventions:

We have seen how entity framework creates DB tables from domain classes in the previous section. Here, we will learn about default Code-First conventions in EF 6.x.

What is Convention?

Conventions are set of default rules which automatically configure a conceptual model based on your domain classes when working with Code-First approach. These EF 6.x Code-First conventions are defined in System.Data.Entity.ModelConfiguration.Conventions namespace.

Let's see an overview of the various Code-First conventions.

Type Discovery:

In the previous section, we created a context class which contains DbSet<TEntity> type properties for the domain classes. Code-First will create tables in the database for all DbSet properties in a context class, as we have seen the previous section.

EF also create DB table for the domain classes which are not included as DbSet properties in a context class but they are included as a reference property in other domain class which is included as DbSet property in a context class. (Even if the referenced types are defined in a different assembly.)

For example, the following Student class includes reference to Teacher class. However, context class does not include Teacher as DbSet property.

public class Student
{
    public int StudentID { get; set; }
    public string StudentName { get; set; }
    public DateTime DateOfBirth { get; set; }
    public byte[]  Photo { get; set; }
    public decimal Height { get; set; }
    public float Weight { get; set; }
        
    public Teacher Teacher { get; set; }
    public Standard Standard { get; set; }
}

public class Teacher
{
    public int TeacherId { get; set; }
    public string TeacherName { get; set; }
}
        

The following is a context class which does not include DbSet type property for Teacher.

namespace EF_Code_First_Tutorials
{
    public class SchoolContext: DbContext 
    {
        public SchoolContext(): base()
        {
        }
            
        public DbSet<Student> Students { get; set; }
        public DbSet<Standard> Standards { get; set; }
    }
}

So, even if Teacher is not included as DbSet type, EF will include it in conceptual model and create a DB table for it, as shown below.

Entity Framework code-first example

Code-First also includes derived classes even if the context class only includes base class as a DbSet property.

The conventions for the type discovery are:

  1. EF creates tables for types defined as a DbSet property in context class.
  2. EF creates table for the reference types included in entity types even if they are defined in different assembly.
  3. EF creates table for the derived classes even if only the base class is defined as DbSet property.

Primary Key Convention:

In the previous section, we have seen that EF automatically creates a Primary Key in each table. By default, EF creates a primary key for a property if a property name is Id or <class name>Id (NOT case sensitive). The data type of a primary key property can be anything, but if it is numeric or GUID then it will be configured as an identity column in DB.

If you have defined key property other than Id or <ClassName>Id then ModelValidationException will be thrown. For example, consider the following Standard class:

public class Student
{
    public int StudID { get; set; }
    public string StudentName { get; set; }
    public DateTime DateOfBirth { get; set; }
    public byte[]  Photo { get; set; }
    public decimal Height { get; set; }
    public float Weight { get; set; }
}

In the above example, Student class is includes StudId property instead of StudentId or Id. So, EF will throw the following exception for not having Key property.

'System.Data.Entity.ModelConfiguration.ModelValidationException' occurred in EntityFramework.dll
EntityType 'Student' has no key defined. Define the key for this EntityType.

Use DataAnnotations or Fluent API to configure StudId property as primary key.

Note: Every entity class must include key property in Entity Framework.

Relationship Convention:

EF 6 infer the One-to-Many relationship using navigation property by default convention. Visit Convention for One-to-Many relationship chapter for more information.

Note: EF 6 does not include default conventions for One-to-One and Many-to-Many relationship. You need to configure it either using Fluent API or DataAnnotation.

Foreign key Convention:

We have seen above that Code First automatically inserts a foreign key when it encounters a navigation property. It is recommended to include a foreign key property on the dependent end of a relationship. Consider the following example:

public class Student
{
    public int StudentID { get; set; }
    public string StudentName { get; set; }
    public DateTime DateOfBirth { get; set; }
    public byte[]  Photo { get; set; }
    public decimal Height { get; set; }
    public float Weight { get; set; }
        
    //Foreign key for Standard
    public int StandardId { get; set; }
    public Standard Standard { get; set; }
}

public class Standard
{
    public int StandardId { get; set; }
    public string StandardName { get; set; }
    
    public IList<Student> Students { get; set; }
}

As you can see in the above code, Student class includes foreign key StandardId, which is the key property in Standard class. Now, Code First will create StandardId column in Students class instead of Standard_StandardId column, as shown below.

Entity Framework code-first example

Notice that StandardId foreign key is not null in the above figure. This is because int data type is not nullable.

Code First infers the multiplicity of the relationship based on the nullability of the foreign key. If the property is nullable then the relationship is registered as null. Otherwise, the relationship is registered as NOT NULL. Modify data type of StandardId property from int to Nullable<int> in the Student class above to create a nullable foreign key column in the Students table.

Complex type Convention:

Code First creates complex type for the class which does not include key property and also primary key is not registered using DataAnnotation or Fluent API.

Default Code-First Conventions:

The following table lists default code first conventions:

Default Convention For Description
Table Name <Entity Class Name> + 's'
EF will create DB table with entity class name suffixed by 's'
Primary key Name 1) Id
2) <Entity Class Name> + "Id" (case insensitive)

EF will create primary key column for the property named Id or <Entity Class Name> + "Id" (case insensitive)
Foreign key property Name By default EF will look for foreign key property with the same name as principal entity primary key name.
If foreign key property does not exists then EF will create FK column in Db table with <Dependent Navigation Property Name> + "_" + <Principal Entity Primary Key Property Name>
e.g. EF will create Standard_StandardId foreign key column into Students table if Student entity does not contain foreignkey property for Standard where Standard contains StandardId
Null column EF creates null column for all reference type properties and nullable primitive properties.
Not Null Column EF creates NotNull columns for PrimaryKey properties and non-nullable value type properties.
DB Columns order EF will create DB columns same as order of properties in an entity class. However, primary key columns would be moved first.
Properties mapping to DB By default all properties will map to database. Use [NotMapped] attribute to exclude property or class from DB mapping.
Cascade delete Enabled By default for all types of relationships.

The following table list C# datatype mapped with SQL datatype and primary key column datatype and length.

C# DataType Related DB Column DataType PK Column DataType & Length
int int int, Identity column increment by 1
string nvarchar(Max) nvarchar(128)
decimal decimal(18,2) decimal(18,2)
float real real
byte[] varbinary(Max) varbinary(128)
datetime datetime datetime
bool bit bit
byte tinyint tinyint
short smallint smallint
long bigint bigint
double float float
char No mapping No mapping
sbyte No mapping
(throws exception)
No mapping
object No mapping No mapping

This was an overview of code first conventions. These conventions can be overriden using DataAnnotation or Fluent API.