Skip to main content

Code First Relationships Fluent API

Julie Lerman
www.thedatafarm.com

Published May, 2011

Download the code for this article:

See this video in action


Entity Framework Code First allows you to use your own domain classes to represent the model which EF relies on to perform querying, change tracking and updating functions. Code first leverages a programming pattern referred to as convention over configuration. What this means is that Code First will assume that your classes follow the conventions of the schema that EF uses for a conceptual model. In that case, EF will be able to work out the details it needs to do its job. However, if your classes do not follow those conventions, you have the ability to add configurations to your classes to provide EF with the information it needs.

Code first gives you two ways to add these configurations to your classes. One is using simple attributes called DataAnnotations and the other is using Code First’s fluent API, which provides you with a way to describe configurations imperatively, in code.

This article will focus on tuning up relationships in the fluent API. Code First conventions are very adept at recognizing common relationships between classes based on properties that point to child collections or to a single class. When your classes don’t use foreign keys, Code First can infer database foreign keys for you.  But there are times when your classes don’t provide enough information for Code First to handle these relationships in the way you intended.

Introducing the Model

I’ll begin with a simple pair of classes, Blog and Post, where Blog has a one-to-many relationship with Posts.

public class Blog
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public string BloggerName { get; set; }
        public virtual ICollection<Post> Posts { get; set; }
    }
    public class Post
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public DateTime DateCreated { get; set; }
        public string Content { get; set; }
        public int BlogId { get; set; }
        public Blog Blog { get; set; }
    }

Understanding Convention for One to Many Relationships

A common way to define one to many relationships in classes is to have a child collection in the one class and then a foreign key property along with a navigation property in the child class. In the above example, Blog has a Posts property which is an ICollection of Post types. Post has a foreign key, BlogID as well as a navigation property, Blog that points back to its parent Blog.

This setup fits into Code First convention’s expectations and as a result, Code First will create the following database tables:


Figure 1

Notice that Code First made the BlogId a database foreign key (there is a Primary Key / Foreign Key constraint defined between Posts.BlogId and Blogs.Id) and that is non-nullable. That is what Code First convention determined from the classes.

Using HasRequired to Help When there is no Foreign Key Property

What if you didn’t want to have a BlogId property in your Post class, but you did have the navigation property, Blog. Code first is able still to create the relationship because it knows that the Blog property points back to the Blog entity. So it will still create the database foreign key, Posts.Blog_Id as you can see in Figure 2, along with a constraint linking it to Blog.Id.

 


Figure 2

But there is one important difference.  Blog_Id is nullable. It will be possible to add Posts that are not bound to a Blog. This is how Code First convention interpreted the class but it is probably not your intention. You can use the fluent API to fix this.

Fluent API configurations are applied as Code First is building the model from the classes. You can inject the configurations by overriding the DbContext class’ OnModelCreating method shown here.

public class BlogContext : DbContext 
    {
        public DbSet<Blog> Blogs { get; set; }
        public DbSet<Post> Posts { get; set; }
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
         //configure model with fluent API
        }

The DbModelBuilder gives you a hook into the configurations. Here we can tell the model builder that we want to affect one of the entities, and you can use generics to specify which entity, Post. Once you have access to that, you can use the HasRequired method, which is particular to relationships, to specify that a navigation property is required — in this case the Blog property.

modelBuilder.Entity<Post>().HasRequired(p => p.Blog);

This will have two effect. First, the Blog_Id field in the database will become not null again. But also, Entity Framework will perform a validation on-demand or prior to saving changes back to the database, to ensure that this requirement has been met.

Configuring Unconventional Foreign Key Names

When you do have a foreign key in the class, that property name may not always match the Code First convention. The convention is that the key is a combination of the name of the class it points to, e.g., Blog, and either _Id or Id. That’s why Code First was able to work with original property in the class, BlogId.

 But what if your property didn’t fit the convention? Perhaps you use “FK” + parent + “Id”?

public int FKBlogId { get; set; }

Code first will have no clue that FKBlogId is supposed to be the foreign key. It will create a standard column to represent that property and it will also create the Blog_Id foreign key that it determined was needed because of the Blog property.

 


Figure 3

Additionally, when you are working with Blog and Post in your code, FKBlogId will never be recognized as the foreign key back to blog. If you have code in place to fix up bi-directional relationships, it won’t do its job using the FKBlogId property.

You can use the fluent API to fix this, telling Code First your true intent, for FKBlogId to be the foreign key property in the relationship to Blog. And you can start with the configuration already in place.

In this configuration you’ll define both ends of the relationship — the property in Blog that points to the many relationship  (Posts) and the property in Post that points back to the parent (Blog).

First you need to add the WithMany method, which allows you to indicate which property in Blog contains the Many relationship.

modelBuilder.Entity<Post>().HasRequired(p => p.Blog)
                .WithMany(b => b.Posts)

Then you can add to that the HasForeignKey method to indicate which property of Post is the foreign key pointing back to blog. In the end, here is the complete mapping:

modelBuilder.Entity<Post>().HasRequired(p => p.Blog)
                .WithMany(b => b.Posts)
                .HasForeignKey(p => p.FKBlogId);

Now Code First has the information it needs to create the correct database schema (or to map correctly to an existing database) and to provide the expected behavior in your application with respect to bi-directional relationships.

 


Figure 4

Defining Join Table Schema in Many to Many Relationships

In your classes you can easily describe a many to many relationship with properties that point to each other. For example, if you added a Tag class to the model to track Tags for Posts, you will need a many to many relationship between the two.

Here is the new Tag class:

public class Tag
    {
        public int TagId{ get; set; }
        public string Name { get; set; }
        public ICollection<Post> Posts { get; set; }
    }

And here is the new property added to the Post class:

public ICollection<Tag> Tags { get; set; }

Code first expects the join table to be named by combining the names of the two classes and to contain the foreign key properties that are each a combination of the class name and the key property. In this case I am working with Post.Id and Tag.TagId. If you are letting Code First create the database, here is what that table will look like using Code First conventions:

 


Figure 5

When you are letting Code First build the database, this may not be a problem. But if you are mapping to an existing database, these namings may not line up at all with your table. You can use the fluent API to describe the table name and both of the column names and you can explicitly name only one, two or all three.

Here’s how to achieve this mapping. Let’s use the example where we’ll need to define all three names. The table should be PostJoinTag and the columns should be TagId and PostId.

You’ll need to start with the Entity mapping method and you can pick either the Post or the Tag to begin with. Here’ll I’ll use Post. Next you need to specify the two ends of the relationship. And similar to how you specified the one-to-many relationship in the previous mapping, you can do that with HasMany and WithMany. Here I’m saying that the Post entity has a many relationship through its Tags property and from there, Tag has a relationship to its Many relationship with its Posts property.

 

modelBuilder.Entity<Post>()
                .HasMany(p => p.Tags)
                .WithMany(t => t.Posts)
                .Map(mc =>
                   {
                       mc.ToTable("PostJoinTag");
                       mc.MapLeftKey("PostId");
                       mc.MapRightKey("TagId");
                   });


Figure 6

You’ll need to take care when specifying which is MapLeftKey and which is MapRightKey. Left will be the key of the first class you pointed to, which is Post, and right is for the other side of the relationship. If you get these backwards, your data will be stored incorrectly and your users will be very confused.

Summary

You’ve seen some of the possibilities for relationship mappings that you can describe with Code First’s fluent API for relationships. Here I’ve fixed up the convention’s misinterpretation of my intent with one to many relationships and many to many relationships. There are additional mappings that you can use, alone or in combination with each other. And while at first they may seem confusing and redundant, for example IsRequired and HasRequired or WithMany and HasMany. But now you’ve seen that the mappings have very specific jobs that there is a reason for them to be different.

Be sure to check the Entity Framework 4.1 MSDN Documentation http://msdn.microsoft.com/en-us/library/gg696172(v=VS.10).aspx and the Entity Framework team blog ( http://blogs.msdn.com/adonet ) to discover more of the relationship mappings you can achieve with the fluent API.

About the Author

Julie Lerman is a Microsoft MVP, .NET mentor and consultant who lives in the hills of Vermont. You can find her presenting on data access and other Microsoft .NET topics at user groups and conferences around the world. Julie blogs at  thedatafarm.com/blog and is the author of the highly acclaimed book, “Programming Entity Framework” (O’Reilly Media, 2009). Follow her on Twitter.com:  julielerman.

Microsoft is conducting an online survey to understand your opinion of the MSDN Web site. If you choose to participate, the online survey will be presented to you when you leave the MSDN Web site.

Would you like to participate?