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:
- The DbModelBuilder.Entity method returns an EntityTypeConfiguration instance for the
Instructor entity
. - The EntityTypeConfiguration.HasOptional method returns an OptionalNavigationPropertyConfiguration instance for the
Instructor.OfficeAssignment
navigation property that specifies that theInstructor
entity may optionally have a relatedOfficeAssignment
entity. - The OptionalNavigationProperty.WithRequired method specifies that an
OfficeAssignment
entity must have a correspondingInstructor
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:
- The DbModelBuilder.Entity method returns an EntityTypeConfiguration instance for the
Course
entity. - The EntityTypeConfiguration.HasMany method returns a ManyNavigationPropertyConfiguration instance for the
Course.Instructors
navigation property that specifies that aCourse
entity may be related to manyInstructor
entities. - 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 theInstructor
entity. - 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
Comments
- Anonymous
October 23, 2011
This shines a tiny light on the subject. Where can I get a readable, full documenation of the Fluent API EF configuration? - Anonymous
October 24, 2011
See this MSDN page for fluent API documentation:msdn.microsoft.com/.../hh295847(VS.103).aspx - Anonymous
October 31, 2012
I'm not sure but in the third statement, Is the HasOptional method specifying a one-to-zero-or-one relationship? I'm following the "Creating a More Complex Data Model" tutorial and there's a zero-or-one-to-many relationship between the Instructor and Department tables.I'm sorry English isn't my main language ;). - Anonymous
July 09, 2013
Will the mapping works without this settings? - Anonymous
July 09, 2013
In most cases you can do the same mapping using annotations that you can do with fluent API. There are a few exceptions that can only be done by using API. For details, see this book: shop.oreilly.com/.../0636920022220.do - Anonymous
January 22, 2014
Find the latest walkininterviews at www.walkininterviews.info - Anonymous
February 02, 2015
Whoever came up with this "Fluent" API is a moron. This is completely incomprehensible, and turns into a gigantic unintelligible mess in the DbContext. Avoid Fluent unless absolutely necessary. Use Attributes instead. - Anonymous
March 24, 2015
Thank you so much! I learned so much!