Configure One-To-Many Relationships In Entity Framework Using Code First Approach

Introduction
 

The relationship between tables is defined by using foreign keys in relational databases. The foreign key is a column or combination of columns that enforces a relationship between the data of two tables. The following three types of relationships are supported:
  1. One to One
  2. One to Many or Many to one
  3. Many to Many
All three types of relationships are supported by the entity framework in the code first approach. In this article, we will cover one-to-many relationships between entities.
 
A one-to-many relationship happens when the primary key of one table becomes foreign keys in another table and also this primary key should participate in the primary key of the second table. In this relationship only zero, one, and more than one recordsare present on either side of tables.
 
Understand One to Many relationships
 
To understand one-to-many relationships, I have created two entities: People and PeopleAddress. One person record has one or more Address records. Here PeopleId is the primary key for the People table and it also participates in the primary key and foreign key of the PeopleAddress table.
 
One to Many relationship
 
Through association, an entity can be related to the other entities in the entity framework. The relation between the entities contains two ends that describe the type of the entity and multiplicity of the type. The two ends of relation can be referred to as the principal role and dependent role.
 
There are two ways to configure one-to-one relations between two entities in Entity Framework
 
Using DataAnnotation
 
Entity Framework Code First provides a set of data annotation attributes that can be applied to domain classes or the properties of domain classes. ForeignKey Attribute specifies the foreign key for the Navigation property in Entity Framework. As discussed earlier, a relationship in the entity framework always has two ends, a navigation property on each side and an Entity Framework that maps them together automatically by convention. If there are multiple relationships between the two entities, Entity Framework cannot handle the relationships. This is because Entity Framework doesn't know which navigation property map with which properties on the other side. InverseProperty attribute can help us to resolve this issue.
 
Example:
 
People POCO class:
  1. [Table("People")]  
  2. public partial class People  
  3. {  
  4.     public People()  
  5.         {  
  6.             this.PeopleAddress = newHashSet < PeopleAddress > ();  
  7.         }  
  8.         [DatabaseGenerated(DatabaseGeneratedOption.None)]  
  9.         [Key]  
  10.     public int PeopleId  
  11.     {  
  12.         get;  
  13.         set;  
  14.     }  
  15.     [Required]  
  16.     [StringLength(50)]  
  17.     public string FirstName  
  18.     {  
  19.         get;  
  20.         set;  
  21.     }  
  22.     [Required]  
  23.     [StringLength(50)]  
  24.     public string LastName  
  25.     {  
  26.         get;  
  27.         set;  
  28.     }  
  29.     public virtual ICollection < PeopleAddress > PeopleAddress  
  30.     {  
  31.         get;  
  32.         set;  
  33.     }  
  34. }  
PeopleAddressPOCO class
  1. [Table("PeopleAddress")]  
  2. public partial class PeopleAddress  
  3. {  
  4.     [Key]  
  5.     [Column(Order = 1)]  
  6.     [DatabaseGenerated(DatabaseGeneratedOption.None)]  
  7.     public int PeopleAddressId  
  8.     {  
  9.         get;  
  10.         set;  
  11.     }  
  12.     [Column(Order = 2)]  
  13.     [Key, ForeignKey("People")]  
  14.     public int PeopleId  
  15.     {  
  16.         get;  
  17.         set;  
  18.     }  
  19.     [Required]  
  20.     [StringLength(100)]  
  21.     public string AddressLine1  
  22.     {  
  23.         get;  
  24.         set;  
  25.     }  
  26.     [Required]  
  27.     [StringLength(100)]  
  28.     public string AddressLine2  
  29.     {  
  30.         get;  
  31.         set;  
  32.     }  
  33.     [StringLength(50)]  
  34.     public string City  
  35.     {  
  36.         get;  
  37.         set;  
  38.     }  
  39.     [StringLength(50)]  
  40.     public string State  
  41.     {   
  42.         get;  
  43.         set;  
  44.     }  
  45.     [StringLength(50)]  
  46.     public string Country  
  47.     {  
  48.         get;  
  49.         set;  
  50.     }  
  51.     public virtual PeoplePeople  
  52.     {  
  53.         get;  
  54.         set;  
  55.     }  
  56. }  
Entity Context class
  1. public partial class EFTestModel: DbContext  
  2. {  
  3.     public EFTestModel(): base("name=entities")  
  4.     {}  
  5.     public virtual DbSet < People > People  
  6.     {  
  7.         get;  
  8.         set;  
  9.     }  
  10.     public virtual DbSet < PeopleAddress > PeopleAddress  
  11.     {  
  12.         get;  
  13.         set;  
  14.     }  
  15.     protected override void OnModelCreating(DbModelBuildermodelBuilder)  
  16.     {}  
  17. }  
In the above example, the People and PeopleAddress class have a one-to-many relationship. Here, PeopleId will become the primary key of the People table and we have used key and ForeignKey attributes for PeopleId property in PeopleAddress class in order to make primary key and foreign key. In the highlighted text in the above code, we have to pass People entity in ForeignKey attribute of PeopleAddress class. Thus, the code first creates a one-to-many relation between Employee and EmployeeDetail class using DataAnnotations attributes.
 
To test the above model, I have created a console application that first gets people entity data and then prints all addresses data on the screen.
  1. static void Main(string[] args)  
  2. {  
  3.     //Configure One to Many Relationship in Entity Framework Using Code First Approach  
  4.     People people;  
  5.     using(var context = newEntityModel.EFTestModel())  
  6.     {  
  7.         people = context.People.FirstOrDefault();  
  8.         int index = 1;  
  9.         Console.WriteLine("People Details");  
  10.         Console.WriteLine("Name:" + string.Join(" ", newobject[]  
  11.         {  
  12.             people.FirstName, people.LastName  
  13.         }));  
  14.         Console.WriteLine("Addresses");  
  15.         Console.WriteLine("---------");  
  16.         for each(var address inpeople.PeopleAddress)  
  17.         {  
  18.             Console.WriteLine(index + string.Join(", ", newobject[]  
  19.             {  
  20.                 address.AddressLine1, address.AddressLine2, address.City, address.State, address.Country  
  21.             }));  
  22.             index += 1;  
  23.         }  
  24.     }  
  25.     Console.ReadLine();  
  26. }  
Output
 
run
 
Using Fluent API
 
For conventions of the primary key and foreign key in code first, we can use "Fluent API". Using "HasKey" method, we can define the primary key. Using “HasForeignKey” method we can define ForeignKey. "HasRequired" or “WithRequired” method is used to make property non-nullable. Using these two methods of fluent API, we can define a foreign key in code first. “HasMany” and “WithMany” method is used to define one-to-many or many-to-many relation in entity framework.
 
We can configure one-to-many relationships between People and PeopleAddress using Fluent API by the following code in the model class:
  1. protected override void OnModelCreating(DbModelBuildermodelBuilder)  
  2. {  
  3.    modelBuilder.Entity<StudentAddress>()  
  4.    .HasRequired<Student>(s =>s.Student)  
  5.    .WithMany(s =>s.StudentAddress)  
  6.    .HasForeignKey(s =>s.StudentId);  
  7.   
  8.   
  9.    // Alternate possible way  
  10.    //modelBuilder.Entity<Student>()  
  11.    // .HasMany<StudentAddress>(s =>s.StudentAddress)  
  12.    // .WithRequired(s =>s.Student)  
  13.    // .HasForeignKey(s =>s.StudentId);  
  14.   
  15. }  
The following are the class definitions for Student and StudentAddress.
  1. [Table("Student")]  
  2. public partial class Student  
  3. {  
  4.     public Student()  
  5.         {  
  6.             this.StudentAddress = newHashSet < StudentAddress > ();  
  7.         }  
  8.         [DatabaseGenerated(DatabaseGeneratedOption.None)]  
  9.     public int StudentId  
  10.     {  
  11.         get;  
  12.         set;  
  13.     }  
  14.     [Required]  
  15.     [StringLength(50)]  
  16.     public string FirstName  
  17.     {  
  18.         get;  
  19.         set;  
  20.     }  
  21.     [Required]  
  22.     [StringLength(50)]  
  23.     public string LastName  
  24.     {  
  25.         get;  
  26.         set;  
  27.     }  
  28.     public virtual ICollection < StudentAddress > StudentAddress  
  29.     {  
  30.         get;  
  31.         set;  
  32.     }  
  33. }  
  34. [Table("StudentAddress")]  
  35. public partial class StudentAddress  
  36. {  
  37.     [DatabaseGenerated(DatabaseGeneratedOption.None)]  
  38.     public int StudentAddressId  
  39.     {  
  40.         get;  
  41.         set;  
  42.     }  
  43.     public int StudentId  
  44.     {  
  45.         get;  
  46.         set;  
  47.     }  
  48.     [Required]  
  49.     [StringLength(100)]  
  50.     public string AddressLine1  
  51.     {  
  52.         get;  
  53.         set;  
  54.     }  
  55.     [Required]  
  56.     [StringLength(100)]  
  57.     public string AddressLine2  
  58.     {  
  59.         get;  
  60.         set;  
  61.     }  
  62.     [StringLength(50)]  
  63.     public string City  
  64.     {  
  65.         get;  
  66.         set;  
  67.     }  
  68.     [StringLength(50)]  
  69.     public string State  
  70.     {  
  71.         get;  
  72.         set;  
  73.     }  
  74.     [StringLength(50)]  
  75.     public string Country  
  76.     {  
  77.         get;  
  78.         set;  
  79.     }  
  80.     public virtual StudentStudent  
  81.     {  
  82.         get;  
  83.         set;  
  84.     }  
  85. }  
To test the above model, I have created a console application and get first student and printed its all address on screen.
  1. static void Main(string[] args)  
  2. {  
  3.     //Configure One to Many Relationship in Entity Framework Using Code First Approach  
  4.     Student student;  
  5.     using(var context = new EntityModel.EFTestModel())  
  6.     {  
  7.         student = context.Student.FirstOrDefault();  
  8.         int index1 = 1;  
  9.         Console.WriteLine("Student Details");  
  10.         Console.WriteLine("Name:" + string.Join(" ", newobject[]  
  11.         {  
  12.             student.FirstName, student.LastName  
  13.         }));  
  14.         Console.WriteLine("Addresses");  
  15.         Console.WriteLine("---------");  
  16.         for each(var address instudent.StudentAddress)  
  17.         {  
  18.             Console.WriteLine(index1 + " " + string.Join(", ", newobject[]  
  19.             {  
  20.                 address.AddressLine1, address.AddressLine2, address.City, address.State, address.Country  
  21.             }));  
  22.             index1 += 1;  
  23.         }  
  24.     }  
  25.     Console.ReadLine();  
  26. }  
Output
 
Output
 

Summary

 
This article helps us to learn how to configure one-to-many relationships between entities in a code first approach using data annotation or fluent API. In the next article we will learn how to configure many-to-many relations in entity framework in code first approach.


Similar Articles