Introduction
Relationship between tables is defined using foreign keys in relational database. The foreign key is a column or combination of columns which enforce relation between data of two tables. There are three types of relationships:
- One to One
- One to Many or Many to one
- Many to Many
All three types of relationship is supported by entity framework in code first approach. In this article we will cover one to one relationship between entities.
A one to one relationship happens when the primary key of one table becomes foreign key in another table. Entity framework enforce the primary key of first table should participate in primary key of second table. In this relationship only one record or zero record is present on either side of tables.
Understand One to One relationship
To understand one to one relationship, I have created two entities: Employee and EmployeeDetails. One employee record has only one detail record. Here EmployeeId is primary key for Employee table and same key is present on primary key and foreign key of EmployeeDetail table.
Through an association an entity can be related to the other entities in entity framework. The relation between the entities contains two ends which describe type of the entity and multiplicity of the type. The two ends of relation can be referred as principal role and dependent role.
There are two ways to configure one to one relation between two entities in Entity Framework
Using DataAnnotation
Entity Framework code first provides a set of data annotation attributes that can be applied on 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 other side. InverseProperty attribute can help us to resolve this issue.
Example
Employee POCO class
- [Table("Employee")]
- public partial class Employee
- {
- [DatabaseGenerated(DatabaseGeneratedOption.None)]
- public int EmployeeId
- {
- get;
- set;
- }
- [Required]
- [StringLength(50)]
- public string FirstName
- {
- get;
- set;
- }
- [Required]
- [StringLength(50)]
- public string LastName
- {
- get;
- set;
- }
- [StringLength(50)]
- public string MiddleName
- {
- get;
- set;
- }
- public virtual EmployeeDetail
- {
- get;
- set;
- }
- }
EmployeeDetail POCO class:
- [Table("EmployeeDetail")]
- public partial class EmployeeDetail
- {
- [Key, ForeignKey("Employee")]
- [DatabaseGenerated(DatabaseGeneratedOption.None)]
- public int EmployeeId
- {
- get;
- set;
- }
- [StringLength(10)]
- public string Gender
- {
- get;
- set;
- }
- [StringLength(255)]
- public string EmailAddress
- {
- get;
- set;
- }
- [StringLength(50)]
- public string PhoneNumber
- {
- get;
- set;
- }
- public virtual EmployeeEmployee
- {
- get;
- set;
- }
- }
Entity Context class - public partial class EFTestModel: DbContext
- {
- public EFTestModel(): base("name=entities")
- {}
- public virtualDbSet < Employee > Employees
- {
- get;
- set;
- }
- public virtual DbSet < EmployeeDetail > EmployeeDetails
- {
- get;
- set;
- }
- protected override void OnModelCreating(DbModelBuildermodelBuilder)
- {}
- }
In above example, Employee and EmployeeDetail class have one to one relation. Here EmployeeId will become primary key of Employee table and we have used key and ForeignKey attributes for employeeId property in EmployeeDetail class in order make primary key and foreign key. In highlighted text in above code, we have to pass Employee entity in ForeignKey attribute of EmployeeDetail class. Thus, Code first creates one to one relation between Employee and EmployeeDetail class using DataAnnotations attributes.
To test the above model, I have created console application and get first employee and print its details on screen.
- static void Main(string[] args)
- {
-
- Employee employee;
- using(var context = newEntityModel.EFTestModel())
- {
- employee = context.Employees.FirstOrDefault();
- Console.WriteLine("Employee Details");
- Console.WriteLine("Employee Name:" + string.Join(" ", newobject[]
- {
- employee.FirstName, employee.LastName
- }));
- Console.WriteLine("Employee Email Address:" + employee.EmployeeDetail.EmailAddress);
- }
- Console.ReadLine();
- }
Output Using Fluent API
For conventions of primary key and foreign key in code first, we can use "Fluent API". Using "
HasKey" method, we can define the primary key. "
HasOptional" method is used to make property nullable and "
WithRequired" specify that entity must have a corresponding relation entity. Using these two methods of fluent API, we can define foreign key in code first.
We can configure one to one relation between Employee and EmployeeDetail using Fluent API by the following code in model class:
- protected override void OnModelCreating(DbModelBuildermodelBuilder)
- {
- modelBuilder.Entity < Customer > ().HasKey(p => p.CustomerId);
- modelBuilder.Entity < Customer > ().HasOptional(e => e.CustomerDetail).WithRequired(e => e.Customer);
- }
The following is the class definition for Customer and CustomerDetail.
- [Table("Customer")]
- public partial class Customer
- {
- [DatabaseGenerated(DatabaseGeneratedOption.None)]
- public int CustomerId
- {
- get;
- set;
- }
- [Required]
- [StringLength(50)]
- public string FirstName
- {
- get;
- set;
- }
- [Required]
- [StringLength(50)]
- public string LastName
- {
- get;
- set;
- }
- [StringLength(50)]
- public string MiddleName
- {
- get;
- set;
- }
- public virtual CustomerDetailCustomerDetail
- {
- get;
- set;
- }
- }
- [Table("CustomerDetail")]
- public partial class CustomerDetail
- {
- [Key]
- [DatabaseGenerated(DatabaseGeneratedOption.None)]
- public int CustomerId
- {
- get;
- set;
- }
- [StringLength(255)]
- public string EmailAddress
- {
- get;
- set;
- }
- [StringLength(50)]
- public string PhoneNumber
- {
- get;
- set;
- }
- public virtual CustomerCustomer
- {
- get;
- set;
- }
- }
To test the above model, I have created console application and first employee is
get and the details are printed on the screen.
- static void Main(string[] args)
- {
-
- Customer c;
- using(var context = newEntityModel.EFTestModel())
- {
- c = context.Customers.FirstOrDefault();
- Console.WriteLine("Customer Details");
- Console.WriteLine("Customer Name:" + string.Join(" ", newobject[]
- {
- c.FirstName, c.LastName
- }));
- Console.WriteLine("Customer Email Address:" + c.CustomerDetail.EmailAddress);
- }
- Console.ReadLine();
- }
Output Summary This article helps us to learn how to configure one to one relation between entities in code first approach using data annotation or fluent API.
In the next article we will learn how to configure one to many relations in entity framework in code first approach.