Entity Framework Core Conventions are default rules by which the Database Schema is created based on Entity classes and DbContext. For example – the table names, column names, relationships, primary & foreign keys are all created based on these conventions.
Page Contents
Let us understand conventions with an example. We have a project containing the following 2 entity classes (i.e. entities), these are Employee and Department. A Department can have one or more employees and so Department is a “Principal Entity”. An employee has to have a Department so it is dependent on the Department. So Employee is a “Dependent Entity”.
We will see Principal and Dependent Entities more on the later half of this tutorial.
// Principal Entity
public class Department
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Employee> Employee { get; } = new List<Employee>(); // Collection Navigation Property
}
// Dependent Entity
public class Employee
{
public int Id { get; set; }
public int DepartmentId { get; set; }
public string Name { get; set; }
public string Designation { get; set; }
public Department Department { get; set; } = null!; // Reference Navigation Property
}
The Database Context for the project is given below.
public class CompanyContext : DbContext
{
public CompanyContext(DbContextOptions<CompanyContext> options) : base(options)
{
}
public DbSet<Employee> Employee { get; set; }
}
We all know that when we run Entity Framework Core migrations then the database will be created with 2 tables – Employee and Department. The conventions will be responsible for creation of the database schemas which are the tables, columns, relationships and so on. Let us look each of them one by one.
The Entity Framework Core Conventions will create the database table is such a way that their names are the same as the DbSet<T> property names defined on the database context.
We have only one DbSet property which is named “Employee” – public DbSet<Employee> Employee { get; set; }. So EF Core will create a database table by the same name i.e. Employee. If we want a differnt name then we can change the name of this property.
This is all simple, but how the second table i.e. “Department” is created since we haven’t defined a DbSet for it. The answer is Entity Framework Core will also create tables for the entity classes that are not included as DbSet properties but are reachable through Reference Navigation Properties given on other entity class.
In the Employee class we have defined a Reference Navigation Property – public Department Department { get; set; }. Through this property Entity Framework Core finds the “Department” entity and so it also creates a Table for it in the database.
Entity Framework Core Conventions creates columns in the database table for all the scalar properties defined in the entity classes. The column names are kept the same as the property name. The Employee class has 4 scalar properties (Id, DepartmentId, Name, Designation) so 4 columns with the same names are created in the Employee table.
Similarly 2 columns with the names Id & Name will be created in the Department table.
Reference and collection properties are used to create relationships between the tables. We will see this in just a moment.
The next thing which comes to your mind is how EF Core decides what data types the columns of the database tables will have. This is done by the fixed mapping rules of C# data types to SQL Server database, see below.
C# Data Type | Mapping to SQL Server Data Type |
---|---|
int | int |
string | nvarchar(Max) |
decimal | decimal(18,2) |
float | real |
bool | bit |
long | bigint() |
datetime | datetime |
short | smallint |
Based on the mapping rules the columns of the 2 tables in our case are:
// Department table
Id INT IDENTITY (1, 1) NOT NULL
Name NVARCHAR (MAX) NOT NULL
// Employee table
Id INT IDENTITY (1, 1) NOT NULL
DepartmentId INT NOT NULL
Name NVARCHAR (MAX) NOT NULL
Designation NVARCHAR (MAX) NOT NULL
Null columns are created for all reference data types and nullable primitive type properties like string?, Nullable, float?.
Note that string? will be configured as optional column in the database, but string will be configured as required column.
Entity Framework Core will create NotNull columns in the database tables for primary key properties and primitive type properties like string, float, int, DateTime.
The EF Core creates the primary key for a database table for the C# property which is named Id or contains “id” text (case insensitive).
For the Employee table the EF Core will create primary key if the Employee entity class includes a property named id, ID, iD, Id, employeeid, EmployeeId, EMPLOYEEID, EmPLoyEEid, etc. For our case “Id” is the primary key for Employee table and “Id” is the primary key for Department table.
The Entity Framework Core Conventions will create foreign key column for each reference navigation property in the entity class. EF Core will also create a foreign key for a given property if the property name matches one of the naming conventions as shown below.
Suppose if we have a property public int DepartmentId { get; set; } on the “Employee” entity then based on the matching rule <navigation property name><principal key property name>, EF Core will create it as the Foreign key.
In our case we don’t have any property that matches the naming rules so EF Core will automatically create foreign key column called DepartmentId in the Employee table. This will be a shadow foreign key since it does not exists in the entity class.
Also note that their is One-to-Many Relationship between these 2 entities. That is one Department can contain many Employees and vice versa.
The tables of a Relational Database like SQL Server can have 3 types of relationship between them.
Let’s see how Entity Framework Core Conventions does this.
We will learn how to apply One-to-Many Relationship between entity classes in Entity Framework Core. Suppose we have 2 database tables – Country & City. We all know there can be many cities in a single country. Which means we can create One-to-Many relationship between these 2 tables.
The Country entity (Country.cs) is the Principal Entity while the City entity (City.cs) depends on the Country entity and so is the Dependent entity.
One-to-Many Realationship can be of 2 types – Required and Optional. A Required relationship ensures that every dependent entity must be associated with some principal entity i.e. the foreign key value cannot be null. While an optional relationship says that the dependent entity need not be associated with any principal entity that is the value of foreign key column can be null in this case.
Start by adding 2 Classes for Country & City tables. We have shown this below.
// Principal Entity
public class Country
{
public int Id { get; set; }
public string Name { get; set; }
}
// Dependent Entity
public class City
{
public int Id { get; set; }
public string Name { get; set; }
}
To create a Many-to-One relationship between these 2 classes we can follow 4 conventions. These conventions are listed below:
On the City class create a reference navigation property pointing to the Country class as shown below:
public class Country
{
public int Id { get; set; }
public string Name { get; set; }
}
public class City
{
public int Id { get; set; }
public string Name { get; set; }
public Country Country { get; set; } //Reference Navigation Property
}
On applying the EF Core Migrations it will produce a one-to-many relationship (foreign key) between the City and Country tables in the database, where City table includes a nullable foreign key called ‘CountryId’, as shown by the image given below.
Another way to create one-to-many relationship is by adding Collection Navigation Property i.e. by adding ICollection type property in the Country class as shown below.
public class Country
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<City> Cities { get; } = new List<City>(); // Collection Navigation Property
}
public class City
{
public int Id { get; set; }
public string Name { get; set; }
}
This will do the same work as the Convention 1 when we apply migrations.
We can also create both Reference & Collection Navigation Properties on the entities to create foreign key relationship (One-to-Many).
public class Country
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<City> Cities { get; } = new List<City>(); // Collection Navigation Property
}
public class City
{
public int Id { get; set; }
public string Name { get; set; }
public Country Country { get; set; } //Reference Navigation Property
}
One the above code see that we have added Reference Navigation Property on the City entity, and Collection Navigation Property on the Country entity.
In this case we use both Reference & Collection navigations and also add a foreign key property called CountryId of type int on the City entity.
public class Country
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<City> Cities { get; } = new List<City>(); // Collection Navigation Property
}
public class City
{
public int Id { get; set; }
public string Name { get; set; }
public int CountryId { get; set; } //Foreign Key
public Country Country { get; set; } = null!; //Reference Navigation Property
}
Notice the null!; construct, which mean it is required so this will make EF Core to create required foreign key. This is because every dependent (City) must be related to some principal (Country), since it’s foreign key property must be set to some value.
To create Optional Foreign key we should remove the null!; construct and place “?” for accepting null values on the foreign key and reference navigation properties. The code is shown below:
public class Country
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<City> Cities { get; } = new List<City>(); // Collection Navigation Property
}
public class City
{
public int Id { get; set; }
public string Name { get; set; }
public int? CountryId { get; set; } //Foreign Key
public Country? Country { get; set; } //Reference Navigation Property
}
Creating One-to-One relationship between entity classes is very simple in Entity Framework Core. All we have to do is add Reference Navigation properties on both the entities.
In the below code I have created One-to-One Relationship between the ‘Country’ & ‘City’ entity classes.
public class Country
{
public int Id { get; set; }
public string Name { get; set; }
public City City { get; set; } // Reference Navigation Property
}
public class City
{
public int Id { get; set; }
public string Name { get; set; }
public int CountryId { get; set; } // Foreign Key required
public Country Country { get; set; } = null!; // Reference Navigation Property
}
We have shown this on the below image:
Remember the null!; construct will make the relationship as required. In the below example we have made the relationship as Optional by not using null!; and applying nullable operation ? on City’s foreign key and reference navigation properties.
public class Country
{
public int Id { get; set; }
public string Name { get; set; }
public City City { get; set; } // Reference Navigation Property
}
public class City
{
public int Id { get; set; }
public string Name { get; set; }
public int? CountryId { get; set; } // Foreign Key optional
public Country? Country { get; set; } // Reference Navigation Property
}
To establish Many-to-Many Relationship between entities we have to include collection navigation property targetting one another on both sides.
public class Country
{
public int Id { get; set; }
public string Name { get; set; }
public List<City> City { get; set; } //Collection Navigation Property
}
public class City
{
public int Id { get; set; }
public string Name { get; set; }
public List<Country> Country { get; set; } //Collection Navigation Property
}
EF Core will implement it by adding a new join table called CityCountry on the database. This new table will contain foreign keys for both the City and Country tables. This topic is covered in more details at Configure Many-to-Many relationship using Fluent API in Entity Framework Core, so do check it.