Friday 15 May 2015

Setting Up One to Many Relationship with Fluent API in Code First

Let's say that we would like to have a one to many relationship between two tables, e.g. User and Article. A User can have many Articles. Below are two ways of how we could specify the models and relationship configuration with Fluent API.

1. Without Having Foreign Key Property in Model
public class Article 
{
 public int Id { get; set; }

 [StringLength(150)]
 [Required]
 public string Title { get; set; }

 [Required]
 public string Description { get; set; }

 [StringLength(500)]
 [Required]
 public string Url { get; set; }

 #region navigation properties
 public virtual User Submitter { get; set; }
 #endregion
}


public class User 
{
 public int Id { get; set; }
 
 [StringLength(100)]
 [Required]
 public string Firstname { get; set; }
 
 [StringLength(100)]
 [Required]
 public string Lastname { get; set; }

 #region navigational property
 public virtual ICollection<Article> Articles { get; set; }
 #endregion
}


protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
 #region Article table
 modelBuilder.Entity<Article>().HasKey(t => t.Id);
 // specify the relationship between the two tables
 modelBuilder.Entity<Article>().HasRequired(t => t.Submitter).WithMany(t => t.Articles);
 #endregion

 #region User table
 modelBuilder.Entity<User>().HasKey(t => t.Id);
 #endregion
}
Before we go further, I would like to say that I prefer to use Data Annotation attributes in a model for validation purpose only for its properties. The database related configurations are done inside OnModelCreating() method.

On the codes above, we do not specify any foreign key property such as 'SubmitterId'. We do this purely in 'code first perspective' only which focuses on models and 'code' relationships between them, not their relational database relationships. So we do not worry on specifying any foreign key property here, we only specify the navigational property.

Please note as well that we do not put a [Required] attribute on the navigation property even though we always want this model to have a navigational property object (i.e. an article must have a submitter). This would create an issue for us later when we want to update an article object only without worrying about submitter. It is better to specify this rule when specifying the relationship in Fluent API.

To let Code First know the relationship we want, we put this on OnModelCreating() method:
modelBuilder.Entity<Article>().HasRequired(t => t.Submitter).WithMany(t => t.Articles);
The validation rule that the navigational property (i.e. submitter) is required is set here.

Code First will generate tables like below:



2. With Foreign Key Property in Model
If we prefer to specify foreign key property in our model, then we can do this way:
// add foreign key property to the model (Article)
public int SubmitterId { get; set; }
The advantage of doing it this way is that we can name it with any name we like.

Then on OnModelCreating() method, we write:
modelBuilder.Entity<Article>().HasRequired(t => t.Submitter).WithMany(t => t.Articles).HasForeignKey(t => t.SubmitterId);

Below are the tables and columns that will be generated:



For setting other configurations using fluent API, please see this post.

No comments: