Configure One-to-Many Relationship:

Here, we will learn how to configure One-to-Many relationship between two entities (domain classes) in Entity Framework 6.x using code-first approach.

Let's configure one-to-many relationship between the following Student and Grade entities where there can be many students in one grade.


public class Student
{
    public int StudentId { get; set; }
    public string StudentName { get; set; }
}
       
public class Grade
{
    public int GradeId { get; set; }
    public string GradeName { get; set; }
    public string Section { get; set; }
}

After implementing one-to-many relationship in the above entities, the database tables for Student and Grade will look like below.

one-to-one relationship in code first

The one-to-many relationship can be configured in the following ways.

  1. By following conventions
  2. By using DataAnnotations attributes
  3. By using Fluent API

Conventions for One-to-Many Relationship:

There are certain conventions in Entity Framework if followed in entity classes (domain classes), will automatically results in one-to-many relationship between two tables in the database. You don't need to configure anything else.

Let's see an example of all the conventions which create in one-to-many relationship.

Convention 1:

We want to establish one-to-many relationship between Student and Grade entities where many students are associated with one Grade. It means each Student entity points to one Grade. This can be achieved by included reference navigation property of type Grade in the Student entity class as shown below.


public class Student
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Grade Grade { get; set; }
}

public class Grade
{
    public int GradeId { get; set; }
    public string GradeName { get; set; }
    public string Section { get; set; }
}

In the above example, the Student class includes reference navigation property of Grade class. So, there can be many Students for a single Grade. This will result in one-to-many relationship between Student and Grade table in the database where Student table includes foreign key Grade_GradeId as shown below (convention for foreign key is <navigationpropertyname>_<PrimaryKeyPropertyName> ).

one-to-one relationship in code first

Notice that the reference property is nullable, so it creates nullable ForeignKey in the Students table. You can configure NotNull foreign key using fluent API.

Note: Entity Framework Core creates Foreign Key column with the same name as Primary Key property name in the principal entity. For the above example, EF core will create FK GradeId not Grade_GradeId.

Convention 2:

Another convention is to include collection navigation property in the entity as shown below.


public class Student
{
    public int StudentId { get; set; }
    public string StudentName { get; set; }
}

public class Grade
{
    public int GradeId { get; set; }
    public string GradeName { get; set; }
    public string Section { get; set; }

    public ICollection<Student> Students { get; set; } 
}

In the above example, the Grade entity includes collection navigation property of type ICollection<Student>. This also results in one-to-many relationship between Student and Grade entities. This example produces the same result in the database as convention 1.

Convention 3:

By including navigation property at both ends will also result in one-to-many relationship.


public class Student
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Grade Grade { get; set; }
}

public class Grade
{
    public int GradeID { get; set; }
    public string GradeName { get; set; }
    public string Section { get; set; }
    
    public ICollection<Student> Student { get; set; }
}

In the above example, the Student entity includes reference navigation property of the Grade type and the Grade entity class includes collection navigation property of the Student type which results in one-to-many relationship. This example produces the same result in the database as convention 1.

Convention 4:

Defining relationship at both ends as convention 3 with foreign key property in dependent entity creates one-to-many relationship.


public class Student
{
    public int Id { get; set; }
    public string Name { get; set; }
    
    public int GradeId { get; set; }
    public Grade Grade { get; set; }
}

public class Grade
{

    public int GradeId { get; set; }
    public string GradeName { get; set; }
    
    public ICollection<Student> Student { get; set; }
}


In the above example, the Student entity include foreign key property GradeId of type int. This will create one-to-many relationship with NotNull foreign key column in the Student table as shown below.

one-to-one relationship in code first

If type of GradeId is nullable int then it will create null foreign key.


public class Student
{
    public int Id { get; set; }
    public string Name { get; set; }

    public int? GradeId { get; set; }
    public Grade Grade { get; set; }
}

The above will create nullable GradeId column in the database because we have used Nullable<int> type (? is a shortcut for Nullable<int>)

Configure One-to-Many Relationship using DataAnnotations Attributes

You can use two DataAnnotations attributes [ForeignKey] and [InverseProperty] to define one-to-many relationship between two entities if entities (domain classes) do not follow the default code-first conventions as described above.

[ForeignKey]:

As we have seen in the convention 4, the Student entity includes foreign key property with the related reference navigation property where foreign key property follows the convention. The [ForeignKey] attribute helps when the entity includes foreign key property which does not follow the convetion. For example, consider the following Student entity.


public class Student
{
    public int Id { get; set; }
    public string Name { get; set; }

    public int StudentGradeId { get; set; }
    public Grade Grade { get; set; }
}

public class Grade
{
    public int GradeId { get; set; }
    public string GradeName { get; set; }

    public ICollection<Student> Student { get; set; }
}


In the above example, the Student entity includes foreign key property StudentGradeId which does not follow the convention. So, here we can apply [ForeignKey] attribute on it to specify the associated navigation property name as shown below.


public class Student
{
    public int Id { get; set; }
    public string Name { get; set; }

    [ForeignKey("Grade")]
    public int StudentGradeId { get; set; }
    public Grade Grade { get; set; }

}

public class Grade
{
    public int GradeId { get; set; }
    public string GradeName { get; set; }

    public ICollection<Student> Student { get; set; }
}

The above will result in one-to-many relationship in the database as shown below.

one-to-one relationship in code first

Alternatively, we may also apply [ForeignKey] attribute on navigation property and specify foreign key property name as below.


public class Student
{
    public int Id { get; set; }
    public string Name { get; set; }

    public int StudentGradeId { get; set; }

    [ForeignKey("StudentGradeId")]        
    public Grade Grade { get; set; }
}

[InverseProperty]

The [InverseProperty] attribute is used when more than one navigation properties are included in both the entities. Visit InverseProperty chapter for more information.

Configure One-to-Many Relationship using Fluent API

Ideally, you should use fluent API when the entities (domain classes) do not follow the conventions. Consider the following Student and Grade entity classes which do not follow the conventions.


public class Student
{
    public int Id { get; set; }
    public string Name { get; set; }

    public int CurrentGradeId { get; set; }
    public Grade CurrentGrade { get; set; }
}

public class Grade
{
    public int GradeId { get; set; }
    public string GradeName { get; set; }
    public string Section { get; set; }

    public ICollection<Student> Students { get; set; }
}

You can configure one-to-many relationship for the above entities using Fluent API by overriding OnModelCreating method in the context class as below.


public class SchoolContext : DbContext
{
    public DbSet<Student> Students { get; set; }
    public DbSet<Grade> Grades { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        // configures one-to-many relationship
        modelBuilder.Entity<Student>()
            .HasRequired<Grade>(s => s.CurrentGrade)
            .WithMany(g => g.Students)
            .HasForeignKey<int>(s => s.CurrentGradeId);          }
    }
}

In the above example, the following code snippet configures the one-to-many relationship.


modelBuilder.Entity<Student>()
    .HasRequired<Grade>(s => s.CurrentGrade)
    .WithMany(g => g.Students)
    .HasForeignKey<int>(s => s.CurrentGradeId);

This will create following tables in the database.

one-to-one relationship in code first

Let's understand the above code step by step.

First, we need to start configuring with any one entity class. So, modelBuilder.Entity<student>() starts with Student entity.

Then,

.HasRequired<grade>(s => s.CurrentGrade)

the above specifies that the Student entity has required CurrentGrade property. This will create NotNull FK column in the DB.

Now, it's time to configure the other end of the relationship – Grade entity.

.WithMany(g => g.Students)

The above specifies that the Grade entity class includes many Student entities. Here, Many infers ICollection type property.

Now, if the Student entity does not follow the Id property convention for foreign key (which it is not following here) then we can now specify the name of foreign key using HasForeignKey method.

.HasForeignKey<int>(s => s.CurrentGradeId);

The above specifies the foreign key property in the Student entity.

Alternatively, you can start configuring relationship with Grade entity instead of Student entity. The following produces the same result as above.


modelBuilder.Entity<Grade>()
    .HasMany<Student>(g => g.Students)
    .WithRequired(s => s.CurrentGrade)
    .HasForeignKey<int>(s => s.CurrentGradeId);

Configure NotNull ForeignKey using Fluent API:

In the convention 1, we have seen that it creates optional one-to-many relationship which creates nullable foreign key column in the database. To make it NotNull column, configure it using Fluent API as shown below.


modelBuilder.Entity<Student>()
    .HasRequired<Grade>(s => s.CurrentGrade)
    .WithMany(g => g.Students);

The HasRequired<t>() method makes it NotNull column in the database.

Configure Cascade Delete using Fluent API:

Cascade delete means automatically deletes child row when related parent row is deleted. For example, if Grade is deleted then all the students in that Grade should also be deleted automatically.


modelBuilder.Entity<Grade>()
    .HasMany<Student>(g => g.Students)
    .WithRequired(s => s.CurrentGrade)
    .WillCascadeOnDelete();