代码改变世界

Entity Framework Code-First(12):Configure One-to-Many

2016-07-05 17:00  追忆似水流年  阅读(278)  评论(0编辑  收藏  举报

Configure One-to-Many Relationship:

Here, we will learn how to configure One-to-Many relationship between two entities in code-first. Take an example of Student and Standard (grade) entities where one Standard can include many Students. So the relation between Student and Standard entities would be one-to-many.

Visit Entity Relationship section to understand how EF manages one-to-one, one-to-many, and many-to-many relationships between the entities.

Configure One-to-Many relationship using DataAnnotations:

Consider the following Student and Standard entity.

public class Student
{
    public Student() { }

    public int StudentId { get; set; }
    public string StudentName { get; set; }

    public virtual Standard Standard { get; set; }
}
       
public class Standard
{
    public Standard()
    {
        Students = new List<Student>();
    }
    public int StandardId { get; set; }
    public string Description { get; set; }

    public virtual ICollection<Student> Students { get; set; }
}

 

In the above example, Student entity includes navigation property Standard and Standard entity includes collection property for Student. This is the default convention to form one-to-many relationship.

We do not need to configure for one-to-many relationships either using DataAnnotations or Fluent API, if entity classes follow this convention.

EF code-first would create one-to-many relationship by adding Standard_StandardId column in the student table as shown below.

one-to-one relationship in code first

Entity includes ForeignKey Id property:

It is recommended to include foreign key property in an entity class. For example, if Student entity includes StandardId property which automatically becomes foreignkey property because it follows the convention for foreignkey <Type Name>Id.

If foreignkey property name is not as per the convention, for example, Student entity uses different name of foreignkey for Standard entity than StandardId then we need to apply ForeignKey attribute on a property.

For example, the following Student entity includes StandardRefId property.

public class Student
{
    public Student() { }

    public int StudentId { get; set; }
    public string StudentName { get; set; }

        public int StdandardRefId { get; set; }
        
    [ForeignKey("StandardRefId")]
    public virtual Standard Standard { get; set; }
}
       
public class Standard
{
    public Standard()
    {
        StudentsList = new List<Student>();
    }
    public int StandardId { get; set; }
    public string Description { get; set; }

    public virtual ICollection<Student> Students { get; set; }
}

 

In the above example, ForeignKey attribute is applied on Standard navigation property to specify foreignkey property name for Standard property. So now, EF will create StandardRefId column as a FK as shown below.

Entity Framework code-first example

Configure One-to-Many relationship using Fluent API:

Here, we will learn configure One-to-Many relationship between Student and Standard entities using Fluent API.

Let’s configure one-to-many for following Student and Standard entities.

public class Student
{
    public Student(){ }

    public int StudentId { get; set; }
    public string StudentName { get; set; }

    public int StandardId { get; set; }

    public virtual Standard Standard { get; set; }
}
       
public class Standard
{
    public Standard()
    {
        StudentsList = new List<Student>();
    }
    public int StandardId { get; set; }
    public string Description { get; set; }

    public virtual ICollection<Student> Students { get; set; }
}

 

Now, you can configure one-to-many as shown below.

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
        //one-to-many 
        modelBuilder.Entity<Student>()
                    .HasRequired<Standard>(s => s.Standard) // Student entity requires Standard 
                    .WithMany(s => s.Students); // Standard entity includes many Students entities

}

 

Suppose Student and Standard entity class doesn't follow Code-First conventions for foreign key. Student class will include a different foreign key name for Standard than StandardId.

public class Student
{
    public Student(){ }

    public int StudentId { get; set; }
    public string StudentName { get; set; }

    //StdId is not following code first conventions name
    public int StdId { get; set; }

    public virtual Standard Standard { get; set; }
}
       
public class Standard
{
    public Standard()
    {
        StudentsList = new List<Student>();
    }
    public int StandardId { get; set; }
    public string Description { get; set; }

    public virtual ICollection<Student> Students { get; set; }
}

 

So now, you can use Fluent API to configure a One-to-Many relationship using Student entity classes, as shown below.

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
        //one-to-many 
        modelBuilder.Entity<Student>()
                    .HasRequired<Standard>(s => s.Standard)
                    .WithMany(s => s.Students)
                    .HasForeignKey(s => s.StdId);

}

 

As you can see, modelBuilder.Entity<Student>().HasRequired<Standard>(s => s.Standard) specifies that Student entity requires NotNull Standard navigation property. .WithMany(s => s.Students).HasForeignKey(s => s.StdId) specifies that the other side of Student (means Standard entity ) can include many Students in Students collection property and foreign key is StdId.

Another possible way: We can also start with Standard entity.

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
        //configure one-to-many
        modelBuilder.Entity<Standard>()
                    .HasMany<Student>(s => s.Students) Standard has many Students
                    .WithRequired(s => s.Standard)  Student require one Standard
                    .HasForeignKey(s => s.StdId);Student includes specified foreignkey property name for Standard
}

 

The code shown above will create the following database:

one-to-one relationship in code first

Notice that StdId is Not Null column. So you must assign Standard with Student entity every time you add or update Student.

Nullable foreign key for one-to-many relationship.

Use HasOptional method instead of HasRequired method to make foreign key column nullable.

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
        //one-to-many 
        modelBuilder.Entity<Student>()
                    .HasOptional<Standard>(s => s.Standard)
                    .WithMany(s => s.Students)
                    .HasForeignKey(s => s.StdId);

}

 

Learn how to configure many-to-many relationship in the next section.