You learned about the Conventions for One-to-Many Relationship. Generally, you don't need to configure one-to-many relationships because EF Core includes enough conventions which will automatically configure them. However, you can use Fluent API to configure the one-to-many relationship if you decide to have all the EF configurations in Fluent API for easy maintenance.
Entity Framework Core made it easy to configure relationships using Fluent API.
Consider the following Student
and Grade
classes where the Grade
entity includes many Student
entities.
public class Student { public int Id { get; set; } public string Name { get; set; } public int CurrentGradeId { 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> Students { get; set; } }
Configure the one-to-many relationship for the above entities using Fluent API by overriding the OnModelCreating
method in the context class, as shown below.
public class SchoolContext : DbContext { protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer("Server=.\\SQLEXPRESS;Database=EFCore-SchoolDB;Trusted_Connection=True"); } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Student>() .HasOne<Grade>(s => s.Grade) .WithMany(g => g.Students) .HasForeignKey(s => s.CurrentGradeId); } public DbSet<Grade> Grades { get; set; } public DbSet<Student> Students { get; set; } }
In the example above, the following code snippet configures the one-to-many relationship:
modelBuilder.Entity<Student>() .HasOne<Grade>(s => s.Grade) .WithMany(g => g.Students) .HasForeignKey(s => s.CurrentGradeId);
Now, to reflect this in the database, execute migration commands, add-migration <name>
and update-database
. The database will include two tables with One-to-Many relationship as shown below.
Let's understand the above code step by step.
Student
or Grade
.
So, modelBuilder.Entity<student>()
starts with the Student
entity.
.HasOne<Grade>(s => s.Grade)
specifies that the Student
entity includes a Grade
type property named Grade
.
Grade
entity. The .WithMany(g => g.Students)
specifies that the Grade
entity class includes many Student
entities.
Here, WithMany
infers collection navigation property..HasForeignKey<int>(s => s.CurrentGradeId);
specifies the name of the foreign key property CurrentGradeId
.
This is optional. Use it only when you have the foreign key Id
property in the dependent class.
The following figure illustrates the above steps:
Alternatively, you can start configuring the relationship with the Grade
entity instead of the Student
entity, as shown below.
modelBuilder.Entity<Grade>() .HasMany<Student>(g => g.Students) .WithOne(s => s.Grade) .HasForeignKey(s => s.CurrentGradeId);
Cascade delete automatically deletes the child row when the related parent row is deleted.
For example, if a Grade
is deleted, then all the Students
in that grade should also be deleted from the database automatically.
Use the OnDelete
method to configure the cascade delete between Student
and Grade
entities, as shown below.
modelBuilder.Entity<Grade>() .HasMany<Student>(g => g.Students) .WithOne(s => s.Grade) .HasForeignKey(s => s.CurrentGradeId) .OnDelete(DeleteBehavior.Cascade);
The OnDelete()
method cascade delete behaviour uses the DeleteBehavior
parameter. You can specify any of the following DeleteBehavior
values, based on your requirement.