MSDN Documentation

Entity Framework: Relationships

Understanding and managing relationships between entities is a fundamental aspect of working with the Entity Framework (EF). EF provides robust mechanisms to define, query, and manipulate one-to-one, one-to-many, and many-to-many relationships.

Types of Relationships

EF supports the following common relationship types:

Defining Relationships

Relationships are typically defined in your entity classes using navigation properties. EF Code First and Database First approaches infer these relationships based on conventions and explicit configurations.

Example: One-to-Many Relationship

Consider a scenario with `Department` and `Employee` entities, where a `Department` can have many `Employees`, but an `Employee` belongs to only one `Department`.

Department Entity


using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

public class Department
{
    [Key]
    public int DepartmentId { get; set; }
    public string Name { get; set; }

    // Navigation property for the collection of employees
    public virtual ICollection<Employee> Employees { get; set; }
}
                

Employee Entity


using System.ComponentModel.DataAnnotations;

public class Employee
{
    [Key]
    public int EmployeeId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }

    // Foreign key property
    public int DepartmentId { get; set; }

    // Navigation property to the parent department
    public virtual Department Department { get; set; }
}
                

In this example:

Many-to-Many Relationship (with Linking Table)

For a many-to-many relationship, such as `Student` and `Course`, you'll need a linking entity.

Student Entity


using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

public class Student
{
    [Key]
    public int StudentId { get; set; }
    public string Name { get; set; }

    public virtual ICollection<StudentCourse> StudentCourses { get; set; }
}
                

Course Entity


using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

public class Course
{
    [Key]
    public int CourseId { get; set; }
    public string Title { get; set; }

    public virtual ICollection<StudentCourse> StudentCourses { get; set; }
}
                

StudentCourse (Linking Entity)


using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

// Composite primary key
[Table("StudentCourses")]
public class StudentCourse
{
    [Key, Column(Order = 0)]
    public int StudentId { get; set; }
    [Key, Column(Order = 1)]
    public int CourseId { get; set; }

    public virtual Student Student { get; set; }
    public virtual Course Course { get; set; }
}
                

Here, `StudentCourse` acts as the join table between `Student` and `Course`.

Configuring Relationships

While conventions often suffice, you can explicitly configure relationships in your `DbContext` using the `OnModelCreating` method:


using Microsoft.EntityFrameworkCore;

public class SchoolContext : DbContext
{
    public DbSet<Department> Departments { get; set; }
    public DbSet<Employee> Employees { get; set; }
    public DbSet<Student> Students { get; set; }
    public DbSet<Course> Courses { get; set; }
    public DbSet<StudentCourse> StudentCourses { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // One-to-Many: Employee to Department
        modelBuilder.Entity<Employee>()
            .HasOne(e => e.Department)
            .WithMany(d => d.Employees)
            .HasForeignKey(e => e.DepartmentId);

        // Many-to-Many: Student to Course via StudentCourse
        modelBuilder.Entity<StudentCourse>()
            .HasKey(sc => new { sc.StudentId, sc.CourseId });

        modelBuilder.Entity<StudentCourse>()
            .HasOne(sc => sc.Student)
            .WithMany(s => s.StudentCourses)
            .HasForeignKey(sc => sc.StudentId);

        modelBuilder.Entity<StudentCourse>()
            .HasOne(sc => sc.Course)
            .WithMany(c => c.StudentCourses)
            .HasForeignKey(sc => sc.CourseId);
    }
}
                

Querying Related Data

EF provides powerful LINQ query capabilities to retrieve related data. Use `.Include()` to eagerly load related entities or rely on lazy loading (if configured).

Eager Loading Employees with their Departments


var employeesWithDepartments = context.Employees
    .Include(e => e.Department)
    .ToList();
                

Eager Loading Students with their Courses


var studentsWithCourses = context.Students
    .Include(s => s.StudentCourses)
        .ThenInclude(sc => sc.Course)
    .ToList();
                

Refer to the official Entity Framework Core Relationships documentation for more advanced configurations and scenarios.