This blogpost explains how you can configure One-To-One, One-to-Many, Many-To-Many entity relationships using Fluent API in Entity Framework Core. Configuring these relationships between entities are important for the implementation of code first approach.
Fluent API provides HasRequired, WithOptional, HasRequired, HasMany, WithRequiredPrincipal, WithMany method to configure different relationships between entities.
You can generate Models if you already have database through Entity Framework Core Database First tutorial. This tutorial uses the Northwind database and generates Model classes. You can implement following configuration using these Northwind Model classes.
By default, EF Core will create a One-To-One relationship if reference navigation property has set on principal as well as dependent entity. The principal entity can have zero-or-one association with the dependent entity. Dependent entity can have only one association with Principal entity.
The following code has a navigation property between Employee and EmployeeAddress entity. EF Core automatically creates a foreign key property as EmployeeID in the EmployeeAddress entity.
public class Employee { public int EmployeeId { get; set; } public string Name { get; set; } public EmployeeAddress Address { get; set; } } public class EmployeeAddress { public int EmployeeAddressId { get; set; } public string Street { get; set; } public string City { get; set; } public string State { get; set; } public string Country { get; set; } public int EmployeeId { get; set; } public Employee Employee { get; set; } }
By convention Entity Framework Core will create One-To-One relationship between Employee and EmployeeAddress tables as Principal entity Employee has reference navigation property for EmployeeAddress entity. And EmployeeAddress has foreign key EmployeeId and reference navigation property Employee.
When Key or ForeignKey properties do not follow conventions you can use Data Annotation or Fluent API to configure relationships between entities.
See the following code I have change EmployeeAddress entity for EmpId property. If I use EmployeeId as column name then by convention EF Core will create foreign key.
public class Employee { public int EmployeeId { get; set; } public string Name { get; set; } public EmployeeAddress Address { get; set; } } public class EmployeeAddress { public int EmployeeAddressId { get; set; } public string Street { get; set; } public string City { get; set; } public string State { get; set; } public string Country { get; set; } public int EmpId { get; set; } public Employee Employee { get; set; } }
You can use the following code in DbContext class to override OnModelCreating method and configure the relationship using Fluent API.
using EF_Core_Fluent_API_Relationship.Entity; using Microsoft.EntityFrameworkCore; namespace EF_Core_Fluent_API_Relationship { public class StoreContext : DbContext { public StoreContext(DbContextOptions options) : base(options) { } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer(connectionString); } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Employee>() .HasOne<EmployeeAddress>(e => e.Address) .WithOne(em => em.Employee) .HasForeignKey<EmployeeAddress>(em => em.EmpId); } public DbSet<Employee> Employees { get; set; } public DbSet<EmployeeAddress> Addresses { get; set; } } }
Employee And EmployeeAddress entities are ready with One-To-One relationship. Create your database and tables using Add-Migration. It creates tables as shown.
When you include reference navigation property only independent entity, Entity Framework Core will create a One-To-Many relationship. Following code creates One-To-Many relationship between Employee and EmployeeAddress entities. One EmployeeAddress can be associated with many Employees.
public class Employee { public int EmployeeId { get; set; } public string Name { get; set; } public int EmployeeAddressId { get; set; } public EmployeeAddress EmployeeAddress { get; set; } } public class EmployeeAddress { public int EmployeeAddressId { get; set; } public string Street { get; set; } public string City { get; set; } public List<Employee> Employees { get; set; } }
Another convention when you include a collection navigation property in principal entity Entity Framework Core will create a One-To-Many relationship.
Configure One-To-Many relationship using Fluent API In the following example, the Employee entity includes a list of EmployeeAddress so one EmployeeAddress(Parent) can be associated with many Employees(Child). It creates a relationship using the Fluent API. One or more family members can be employees of the same organization.
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<EmployeeAddress>() .HasOne<Employee>(e => e.Employee) .WithMany(g => g.EmployeeAddress) .HasForeignKey(s => s.EmployeeId); }
This generates tables as shown below
Notice it created a Non-Unique index for the EmployeeAddressId column of the Employee table.
Cascade delete is always a unidirectional operation from Principal entity to dependent entity, which means deleting Principal entity will result in deletion of the dependent entity.
The OnDelete method takes DeleteBehavior enum value as an input parameter.
Following code sets DeleteBehavior.Restrict on EmployeeAddress and Employee relationship. So whenever EmployeeAddress is deleted there will be no effect on Employee entity.
modelBuilder.Entity<Employee>() .HasOne<EmployeeAddress>(e => e.EmployeeAddress) .WithMany(g => g.Employees) .HasForeignKey(s => s.EmployeeAddressId).OnDelete(DeleteBehavior.Restrict);
Entity Framework Core does not have a convention for Many-To-Many relationships. You will have to use the Fluent API.
To create One-To-Many relationship in EF Core you will have to create a linking entity class that links two different entities and then add navigation properties to either side of the many-to-many relations that point to the join entity instead.
The linking entity will have separate One-To-Many relationship with two different linked entities.
For example, One Employee can work for many departments and one Department will have many Employees, to configure this relationship we will have to have a linking entity like DeptEmployee. Linking entity which is DeptEmployee will have One-To-Many relationship with the Department as well as Employee entity.
The following code creates an Employee, Department, DeptEmployee entities.
public class Employee { public int EmployeeId { get; set; } public string Name { get; set; } public virtual ICollection<DeptEmployee> DeptEmployee { get; set; } } public class Department { public int DepartmentID { get; set;} public string DeptName {get; set;} public virtual ICollection<DeptEmployee> DeptEmployee { get; set; } } public class DeptEmployee { public int DeptEmpID {get; set;} public int EmployeeId { get; set; } public Employee Employee { get; set; } public int DepartmentId { get; set; } public Department Department { get; set; } }
Update your OnModelCreating method and DBContext class as shown below.
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<DeptEmployee>() .HasKey(de => new { de.EmployeeId, de.DepartmentId }); } public DbSet<Employee> Employees { get; set; } public DbSet<Department> Departments { get; set; } public DbSet<DeptEmployee> DeptEmployees { get; set; }
Now you can use Add-Migration and Update-Database -verbose to create the database. It generates below table schema and database.