Entity Framework Code First Tutorial Supplement: What is Going on in a Fluent API Call

In the new Entity Framework Code First MVC tutorial series there are some examples of what has come to be called fluent API method calls. This term refers to code in which a series of method calls are chained together. The Creating a More Complex Data Model tutorial briefly explains what this code does, but some readers of the tutorial expressed an interest in getting a more in-depth explanation, so I am providing that here, along with links to the relevant API reference documentation.

Here is the code block in question:

 public class SchoolContext : DbContext
{
    public DbSet<Course> Courses { get; set; }
    public DbSet<Department> Departments { get; set; }
    public DbSet<Enrollment> Enrollments { get; set; }
    public DbSet<Instructor> Instructors { get; set; }
    public DbSet<Student> Students { get; set; }
    public DbSet<OfficeAssignment> OfficeAssignments { get; set; }

    protected override void OnModelCreating
       (DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
        modelBuilder.Entity<Instructor>()
            .HasOptional(p => p.OfficeAssignment)
            .WithRequired(p => p.Instructor);
        modelBuilder.Entity<Course>()
            .HasMany(c => c.Instructors)
            .WithMany(i => i.Courses)
            .Map(t => t.MapLeftKey("CourseID")
                .MapRightKey("InstructorID")
                .ToTable("CourseInstructor")); 
        modelBuilder.Entity<Department>()
            .HasOptional(x => x.Administrator); 
    }
}

HasOptional and WithRequired

The first of the mapping API method calls specifies a one-to-zero-or-one relationship between the Instructor and OfficeAssignment entities:

 modelBuilder.Entity<Instructor>()
    .HasOptional(p => p.OfficeAssignment).WithRequired(p => p.Instructor);

Here is what's happening in this code:

  1. The DbModelBuilder.Entity method returns an EntityTypeConfiguration instance for the Instructor entity.
  2. The EntityTypeConfiguration.HasOptional method returns an OptionalNavigationPropertyConfiguration instance for the Instructor.OfficeAssignment navigation property that specifies that the Instructor entity may optionally have a related OfficeAssignment entity.
  3. The OptionalNavigationProperty.WithRequired method specifies that an OfficeAssignment entity must have a corresponding Instructor entity. (The method returns a ForeignKeyNavigationPropertyConfiguration instance that you could use for further configuration, but no more is required for this relationship.)

HasMany and WithMany

The second statement specifies the table and column names for the join table of the many-to-many relationship between the Instructor and Course entities. Code First can configure the many-to-many relationship for you without this code, but if you don't call it, you will get default names such as InstructorInstructorID for the InstructorID column.

 modelBuilder.Entity<Course>()
    .HasMany(c => c.Instructors).WithMany(i => i.Courses)
    .Map(t => t.MapLeftKey("CourseID")
        .MapRightKey("InstructorID")
        .ToTable("CourseInstructor"));

Here is what's happening in this code:

  1. The DbModelBuilder.Entity method returns an EntityTypeConfiguration instance for the Course entity.
  2. The EntityTypeConfiguration.HasMany method returns a ManyNavigationPropertyConfiguration instance for the Course.Instructors navigation property that specifies that a Course entity may be related to many Instructor entities.
  3. The ManyNavigationPropertyConfiguration.WithMany method returns a ManyToManyNavigationPropertyConfiguration instance that specifies that this is a many-to-many relationship and Courses is the corresponding navigation property in the Instructor entity.
  4. The ManyToManyNavigationPropertyConfiguration.Map method lets you configure the tables and columns used for this many-to-many relationship. It takes a ManyToManyAssociationMappingConfiguration instance in which you specify the column names by calling the MapLeftKey, MapRightKey, and ToTable methods. The "left" key is the one specified in the HasMany method; the "right" key is the one specified in the WithMany method.

HasOptional

In the third statement, the HasOptional statement specifies a one-to-zero-or-one relationship between the Department and Instructor tables, represented by the Department.Administrator navigation property:

 modelBuilder.Entity<Department>()
    .HasOptional(x => x.Administrator);

This code is identical to the one for the Instructor-to-OfficeAssignment relationship, except that in the Department-to-Instructor relationship, an Instructor entity does not have to have a corresponding Department, so the WithRequired method is not called.

-- Tom Dykstra
ASP.NET Developer Guidance