Self-Referencing Relationship in Entity Framework Core

Self-Referencing Relationship in Entity Framework Core

In this article, I will discuss How to Configure Self-Referencing Relationships in Entity Framework Core using Fluent API with Examples. Please read our previous article, which discusses How to Configure Many-to-Many Relationships in EF Core using Fluent API.

Self-Referencing Relationship in Entity Framework Core

A self-referencing relationship in Entity Framework Core (EF Core) occurs when an entity has a relationship with instances of the same entity type. This is useful for scenarios where an entity is related to other entities of the same type, such as in hierarchical structures like organizational charts or comments on a post.

A self-referencing relationship, also known as a recursive relationship, occurs when an entity is related to itself. An example scenario is in an organizational structure where an Employee can have a manager who is also an Employee.

Similar to a self-referencing relationship in a relational database, an entity can have a relationship with instances of the same entity type. For example, an Employee entity can have a Manager navigation property that points to another Employee. Let’s say we have an entity called Employee that has a self-referencing relationship to represent a manager-subordinate relationship:

namespace EFCoreCodeFirstDemo.Entities
{
    public class Employee
    {
        public int EmployeeId { get; set; }
        public string? Name { get; set; }
        // ForeignKey for Manager
        public int? ManagerId { get; set; }
        // Navigation property for Manager
        public Employee? Manager { get; set; }
        // Navigation property for Subordinates 
        public List<Employee>? Subordinates { get; set; }
    }
}

In the above example, an Employee entity has a Manager navigation property that points to another Employee, representing the manager of the current employee representing the one-to-one relationship. Additionally, it has a collection navigation property called Subordinates to represent the employees who report to the current employee, representing the one-to-many relationships. In this model:

  • ManagerId is a foreign key pointing to another Employee (the manager).
  • Manager is a reference navigation property pointing to the manager.
  • Subordinates is a collection navigation property containing all Subordinates (employees) under the current Employee.

To configure the self-referencing relationship, we need to use Fluent API in the OnModelCreating method of our DbContext class. So, modify the EFCoreDbContext class as follows:

using Microsoft.EntityFrameworkCore;
namespace EFCoreCodeFirstDemo.Entities
{
    public class EFCoreDbContext : DbContext
    {
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            //Configuring the Connection String
            optionsBuilder.UseSqlServer(@"Server=LAPTOP-6P5NK25R\SQLSERVER2022DEV;Database=EFCoreDB;Trusted_Connection=True;TrustServerCertificate=True;");
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            //Configuring the Employee Entity to Represent Self-Referential Relationships
            modelBuilder.Entity<Employee>()
            .HasOne(e => e.Manager)              // Specifies that each employee has one manager.
            .WithMany(e => e.Subordinates)       // Specifies that each manager can have many Subordinates
            .HasForeignKey(e => e.ManagerId)     // Specifies the foreign key property for this relationship.
            .OnDelete(DeleteBehavior.Restrict);  // Optional: Configure delete behavior
        }

        public DbSet<Employee> Employees { get; set; }
    }
}

In this configuration, we use the HasOne and WithMany methods to define the self-referencing relationship between Employee and himself. The HasForeignKey method specifies the foreign key property (ManagerId) in the Employee table. You can also specify the delete behavior using the OnDelete method, which determines what happens to related entities when an entity is deleted. In this Fluent API configuration:

  • HasOne(e => e.Manager): Specifies that each Employee has one Manager (who is also an Employee).
  • WithMany(m => m.Subordinates): Specifies that an Employee (as a manager) can have many Subordinates.
  • HasForeignKey(e => e.ManagerId): Specifies the foreign key property for the relationship.

Note: Before Proceeding further, let us delete the EFCoreDB database using SSMS and Migration folder from our project.

With the above changes, open the Package Manager Console and Execute the add-migration and update-database commands as follows. You can give any name to your migration. Here, I am giving EFCoreDBMig1. The name that you are giving it should not be given earlier.

How to Configure Self-Referencing Relationship in EF Core using Fluent API

Now, if you verify the database, you should see the following.

How to Configure Self-Referencing Relationship in EF Core using Fluent API with Examples

Next, modify the Main method of the Program class as follows.

using EFCoreCodeFirstDemo.Entities;
namespace EFCoreCodeFirstDemo
{
    internal class Program
    {
        static void Main(string[] args)
        {
            try
            {
                using var context = new EFCoreDbContext();

                //Create a Manager
                Employee mgr = new Employee() { Name = "Pranaya"};
                context.Add(mgr);
                context.SaveChanges();
                Console.WriteLine("Manager Added");

                Employee emp1 = new Employee() { Name ="Hina", ManagerId = 1};
                context.Add(emp1);
                Employee emp2 = new Employee() { Name ="Ramesh", ManagerId = 1 };
                context.Add(emp2);
                context.SaveChanges();
                Console.WriteLine("Employees Added");

                //List of Employee including Manager
                var listOfEmployees = context.Employees.ToList();
                Console.WriteLine("List of Employees");
                foreach (var emp in listOfEmployees)
                {
                    Console.WriteLine($"\tEmployee ID:{emp.Name}, Name:{emp.Name}");
                }

                //List of Subordinates working under Manager whose Id = 1
                var Manager = context.Employees.Find(1);
                if( Manager != null )
                {
                    Console.WriteLine($"\nList of Employees working under Manager : {Manager.Name}");
                    if (Manager.Subordinates != null)
                    {
                        foreach (var emp in Manager.Subordinates)
                        {
                            Console.WriteLine($"Employee ID:{emp.Name}, Name:{emp.Name}");
                        }
                    }
                }
                
                Console.ReadKey();
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error: {ex.Message}"); ;
            }
        }
    }
}
Output:

How to Configure Self-Referencing Relationship in Entity Framework Core using Fluent API with Examples

In the next article, I will discuss Entity Configurations using Entity Framework Core Fluent API with Examples. In this article, I explain How to Configure Self-Referencing Relationships in Entity Framework Core using Fluent API with Examples. I hope you enjoyed this article.

Leave a Reply

Your email address will not be published. Required fields are marked *