Summary: in this tutorial, you’ll learn about one-to-many relationships and how to implement them in EF Core.
Introduction to one-to-many relationships
In the relational database, a one-to-many relationship is a common type of relationship between two tables where a row in a table can associate with multiple rows in another table.
For example, a department can have multiple employees while an employee belongs to one department. Therefore, the Departments has a one-to-many relationship with the Employees table.
The one-to-many relationship is also known as the parent-child relationship. The Departments is called a parent table while the Employees table is called a child table.
To establish the one-to-many relationship between the Departments and Employees tables, the Employees table needs to have a foreign key column called DepartmentId that references the Id column of the Employees table:

If the DepartmentId column accepts NULL, you can insert a row into the Employees table without specifying a corresponding row in the Departments table. In this case, the employee doesn’t belong to any department.
However, if the DepartmentId column doesn’t accept NULL, you need to use an Id from the Departments table for inserting a new row into the Employees table. In this case, an employee must belong to a specific department. In other words, you need to have at least one row in the Departments table first before you can insert rows into the Employees table.
We will demonstrate typical scenarios so that you can model one-to-many relationships between entities. For comprehensive scenarios, you can reference this page.
Modeling required one-to-many relationship
The following shows how to model a required one-to-many relationship between the Department and Employee entities:
public class Department
{
public int Id { get; set; }
public required string Name { get; set; }
// Collection navigation containing children
public ICollection<Employee> Employees { get; set; }
}
public class Employee
{
public int Id { get; set; }
public required string FirstName { get; set; }
public required string LastName { get; set; }
public required decimal Salary { get; set; }
public required DateTime JoinedDate { get; set; }
// Required foreign key property
public int DepartmentId { get; set; }
// Required reference navigation to parent
public Department Department { get; set; } = null!;
}Code language: C# (cs)In this example:
- The
Departmentclass has a property that is a collection ofEmployeeobjects. - The
Employeeclass has two propertiesDepartmentIdandDepartment. TheDepartmentIdis called a foreign key property, which is marked as required. This makes the one-to-many relationship required because eachEmployeemust associate with at least aDepartment. TheDepartmentproperty is known as a navigation property.
Based on this model, EF Core generates the Departments and Employees table in the SQL Server database with the following structure:
CREATE TABLE [dbo].[Departments] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[Name] NVARCHAR (MAX) NOT NULL,
CONSTRAINT [PK_Departments] PRIMARY KEY CLUSTERED ([Id] ASC)
);
GO
CREATE TABLE [dbo].[Employees] (CREATE TABLE [dbo].[Employees] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[FirstName] NVARCHAR (MAX) NOT NULL,
[LastName] NVARCHAR (MAX) NOT NULL,
[Salary] DECIMAL (18, 2) NOT NULL,
[JoinedDate] DATETIME2 (7) NOT NULL,
[DepartmentId] INT NOT NULL,
CONSTRAINT [PK_Employees] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_Employees_Departments_DepartmentId] FOREIGN KEY ([DepartmentId]) REFERENCES [dbo].[Departments] ([Id]) ON DELETE CASCADE
);
GO
CREATE NONCLUSTERED INDEX [IX_Employees_DepartmentId]
ON [dbo].[Employees]([DepartmentId] ASC);
Code language: SQL (Structured Query Language) (sql)Note that the DepartmentId column in the Employees table is not NULL. Also, it is a foreign key that references the Id column of the Departments table.
Modeling the optional one-to-many relationship
The following changes the DepartmentId foreign key property and Departments navigation property of the Employee class to nullable:
public class Department
{
public int Id { get; set; }
public required string Name { get; set; }
public ICollection<Employee> Employees { get; set; }
}
public class Employee
{
public int Id { get; set; }
public required string FirstName { get; set; }
public required string LastName { get; set; }
public required DateTime JoinedDate { get; set; }
public int? DepartmentId { get;set; }
public Department? Department { get; set; }
}Code language: C# (cs)Since the DepartmentId and Department properties are nullable, you can create an Employee object without a Department.
EF Core creates the following Departments and Employees tables in the database. Notice that the DepartmentId in the Employees table accepts NULL:
CREATE TABLE [dbo].[Departments] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[Name] NVARCHAR (MAX) NOT NULL,
CONSTRAINT [PK_Departments] PRIMARY KEY CLUSTERED ([Id] ASC)
);
CREATE TABLE [dbo].[Employees] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[FirstName] NVARCHAR (MAX) NOT NULL,
[LastName] NVARCHAR (MAX) NOT NULL,
[JoinedDate] DATETIME2 (7) NOT NULL,
[DepartmentId] INT NULL,
CONSTRAINT [PK_Employees] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_Employees_Departments_DepartmentId] FOREIGN KEY ([DepartmentId]) REFERENCES [dbo].[Departments] ([Id])
);
GO
CREATE NONCLUSTERED INDEX [IX_Employees_DepartmentId]
ON [dbo].[Employees]([DepartmentId] ASC);
Code language: SQL (Structured Query Language) (sql)Summary
- EF Core uses conventions to infer the one-to-many relationships between model classes and create the corresponding tables in the database.