One-to-One Relationships in Entity Framework Core

One-to-One Relationships in Entity Framework Core using Fluent API

In this article, I will discuss How to configure the One-to-One Relationships between two entities in Entity Framework Core (EF Core) using Fluent API with Examples. Please read our previous article discussing Relationships Between Entities in EF Core.

One-to-One Relationships in Entity Framework Core

In the One-To-One relationship, a row in Table A can have no more than one matching row in Table B, and vice versa. A one-to-one relationship is created if both of the related columns are primary keys or have unique constraints. 

EF Core establishes a one-to-one relationship when both entities have a reference navigation property pointing to the other entity. Annotations like [ForeignKey] and [InverseProperty] are often used to define the relationship explicitly, and we have already discussed these things. I will discuss Implementing One-to-One Relationships in EF Core using Fluent API Configuration in this article.

Examples of Understanding One-to-One Relationships in EF Core

In Entity Framework Core (EF Core), we can define the one-to-one relationship between two entities using the Fluent API Configurations. The Fluent API provides a way to configure the relationships and mappings between two entities in a more flexible and detailed manner than using only data annotations.

In Entity Framework Core (EF Core), a one-to-one relationship means that one entity can be related to only one instance of another entity and vice versa. One-to-one relationships can be either:

  • Principal to Dependent: Here, the dependent end has the foreign key.
  • Shared Primary Key: Here, the dependent uses the primary key from the principal entity as its own primary key.
Principal to Dependent Relationship

In this scenario, one entity (Principal) is related to another entity (Dependent). The dependent entity contains a foreign key pointing to the principal entity’s unique or primary key. The foreign key in the Dependent Entity is applied with the unique constraint, ensuring the one-to-one nature of the relationship.

Let us understand How to Implement One-to-One Relationships in EF Core using Fluent API Configuration with an example. We will implement the One-to-Zero or One-to-One relationship between the following Person and Passport entities. Each person can have only one passport, and each passport belongs to one person.

Person.cs

So, first, create a class file with the name Person.cs and then copy and paste the following code into it. As you can see, this is a very simple class having a few scaler properties and a reference navigation property of the Passport entity.

namespace EFCoreCodeFirstDemo.Entities
{
    public class Person
    {
        public int PersonId { get; set; }
        public string Name { get; set; }
        public Passport Passport { get; set; }
    }
}
Passport.cs

Next, create another class file with the name Passport.cs and copy and paste the following code. As you can see, this class contains a few scaler properties and a reference navigation property pointing to the Person entity.

namespace EFCoreCodeFirstDemo.Entities
{
    public class Passport
    {
        public int PassportId { get; set; }
        public string PassportNumber { get; set; }
        public int PersonId { get; set; }  // Foreign Key
        public Person Person { get; set; }
    }
}

Now, we need to configure the above Person and Passport entities in such a way that EF Core should create the Person and Passport tables in the Database and make the PersonId column in the Person table as the Primary Key (PK) and PersonId column in the Passport table as Foreign Key (FK) and should apply the Unique Constraints on the PersonId Foreign Key Column.

Note: In the One-To-One or One-To-Zero relationship, a row in Table A can have a maximum of one or zero matching rows in Table B, and vice versa is also true.

How to Configure One-to-One Relationship using Fluent API?

We can configure the One-to-One required relationship between two entities using both the Data Annotation Attribute and Fluent API. We have already discussed configuring the One-to-One relationship between the two entities using the ForeignKey Data Annotation Attribute.

Now, let us proceed and try to understand how to Configure the One-to-One relationships between two entities using Entity Framework Core Fluent API. To implement this, we must use the following HasOne(), WithOne(), and HasForeignKey() Fluent API methods.

  • HasOne(): The HasOne() method specifies the navigation property that represents the principal end of the relationship.
  • WithOne(): The WithOne() method specifies the navigation property on the dependent side.
  • HasForeignKey<TDependent>(): The HasForeignKey<TDependent>() method is used to specify which property in the dependent entity represents the foreign key.

Next, modify the context class as follows. The following code sets a one-to-one required relationship between the Person and Passport entities using Entity Framework Core Fluent API.

using Microsoft.EntityFrameworkCore;
namespace EFCoreCodeFirstDemo.Entities
{
    public class EFCoreDbContext : DbContext
    {
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            //Configuring the Connection String
            optionsBuilder.UseSqlServer(@"Server=LAPTOP-6P5NK25R\SQLSERVER2022DEV;Database=EFCoreDB;Trusted_Connection=True;TrustServerCertificate=True;");
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            // Fluent API Configuration
            // Configure One to One Relationships Between Person and Passport
            modelBuilder.Entity<Person>()
            .HasOne(p => p.Passport) //Person has one Passport
            .WithOne(p => p.Person) //Passport is associated with one Person
            .HasForeignKey<Passport>(p => p.PersonId); //Foreign key in Passport table
        }

        public DbSet<Person> Persons { get; set; }
        public DbSet<Passport> Passports { get; set; }
    }
}

In the context class, we must configure the relationship using Fluent API within the OnModelCreating method. The following code configures the One-to-One relationship between the Person and Passport entities.

How to configure the One-to-One Relationships between two entities in Entity Framework Core (EF Core) using Fluent API with Examples

Let’s understand the above code step by step.

  • modelBuilder.Entity<Person>() starts configuring the Person entity. Whichever entity you want to configure using Fluent API, you need to start configuring using the Entity method, and to this generic method, we need to specify the entity type. In this case, it is the Person Entity.
  • HasOne(p => p.Passport) method specifies that the Person entity includes one Passport reference property using a lambda expression. It configures a relationship where this entity type, i.e., Person entity, has a reference that points to a single instance of the other entity, i.e., Passport in the relationship. That means a Person has one Passport.
  • WithOne(p => p.Person) configures the other end of the relationship, the Passport entity. It specifies that the Passport entity includes a reference navigation property of Person type. Configures this as a one-to-one relationship. That means one Passport is associated with one Person.
  • HasForeignKey<Passport>(p => p.PersonId) specifies the foreign key property name. It configures the property, i.e., PersonId, as the foreign key for this relationship. That means it specifies the dependent entity’s foreign key property name.

Note: Before Proceeding further, let us delete the EFCoreDB database using SSMS and Migration folder from our project.

With the above changes, open the Package Manager Console and Execute the add-migration and update-database commands as follows. You can give any name to your migration. Here, I am giving EFCoreDBMig1. The name that you are giving it should not be given earlier.

How to Configure One-to-One Relationship using Fluent API?

Now, if you verify the database, you should see the following.

One-to-One Relationships in Entity Framework Core

Further, if you verify the Passport table, you will see that it applies the Unique Index on the PersonId column, as shown in the image below. This unique index allows the column value to be unique, and the value must be an existing PersonId, hence implementing a One-to-One Relationship.

Examples of Understanding One-to-One Relationships in EF Core

Next, modify the Main method of the Program class as follows. We have specified the Passport reference property here while creating the Person Entity.

using EFCoreCodeFirstDemo.Entities;
using System.Net;

namespace EFCoreCodeFirstDemo
{
    internal class Program
    {
        static void Main(string[] args)
        {
            try
            {
                //Creating an Instance of the Context Class
                using EFCoreDbContext context = new EFCoreDbContext();

                //Creating an Instance of Passport Entity
                var passport = new Passport() { PassportNumber = "Pass-1224-xyz"};

                //Creating Person Entity, configuring the Related Passport Entity
                var Person = new Person() { Name = "Pranaya", Passport = passport };

                context.Persons.Add(Person);
                context.SaveChanges();
                Console.WriteLine("Person and Passport Added");
                Console.ReadKey();
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error: {ex.Message}"); ;
            }
        }
    }
}

Now, run the application and verify the database. You should see both Persons and Passports database tables filled with one record, as shown below.

Principal to Dependent Relationship

Shared Primary Key Relationship

In this case, the dependent entity shares the primary key of the principal entity. This means that the primary key in the dependent entity is both a primary key and a foreign key to the principal entity.

Let us consider the following User and UserProfile Entities. Each user has one profile, and each profile belongs to one user. The profile uses the same primary key as the user.

User.cs

So, first, create a class file named User.cs and copy and paste the following code. As you can see, this is a very simple class having a few scaler properties and a reference navigation property of the UserProfile entity.

namespace EFCoreCodeFirstDemo.Entities
{
    public class User
    {
        public int UserId { get; set; }
        public string Username { get; set; }
        public UserProfile UserProfile { get; set; }
    }
}
UserProfile.cs

Next, create another class file named UserProfile.cs and copy and paste the following code. As you can see, this class contains a few scaler properties and a reference navigation property pointing to the User entity.

using System.ComponentModel.DataAnnotations;
namespace EFCoreCodeFirstDemo.Entities
{
    public class UserProfile
    {
        [Key]
        public int UserId { get; set; }  // PK and FK
        public string Bio { get; set; }
        public User User { get; set; }
    }
}

When the Primary Key (PK) of one table becomes the Primary Key (PK) and Foreign Key (FK) in another table in a relational database such as SQL Server, MySQL, Oracle, etc., then it is said to be in a One-to-One or One-to-Zero relationship between the two database tables.

So, we need to configure the above User and UserProfile entities in such a way that EF Core should create the User and UserProfile tables in the Database and make the UserId column in the User table as the Primary Key (PK) and UserId column in the UserProfile table as Primary Key (PK) and Foreign Key (FK).

Next, modify the context class as follows. The following code sets a one-to-one required relationship between the User and UserProfile entities using Entity Framework Core Fluent API.

using Microsoft.EntityFrameworkCore;
namespace EFCoreCodeFirstDemo.Entities
{
    public class EFCoreDbContext : DbContext
    {
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            //Configuring the Connection String
            optionsBuilder.UseSqlServer(@"Server=LAPTOP-6P5NK25R\SQLSERVER2022DEV;Database=EFCoreDB;Trusted_Connection=True;TrustServerCertificate=True;");
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            // Fluent API Configuration
            // Configure One to One Relationships User Person and UserProfile
            modelBuilder.Entity<User>()
                .HasOne(u => u.UserProfile) //Person has one UserProfile
                .WithOne(up => up.User) //One UserProfile is associated with one User
                .HasForeignKey<UserProfile>(up => up.UserId); //Foreign key in UserProfile table
        }

        public DbSet<User> Users { get; set; }
        public DbSet<UserProfile> UserProfiles { get; set; }
    }
}

Note: Before Proceeding further, let us delete the EFCoreDB database using SSMS and Migration folder from our project.

With the above changes, open the Package Manager Console and Execute the add-migration and update-database commands as follows. You can give any name to your migration. Here, I am giving EFCoreDBMig1. The name that you are giving it should not be given earlier.

One-to-One Relationships in EF Core

Now, if you verify the database, you should see the following.

One-to-One Relationships in EF Core using Fluent API Configuration

Next, modify the Main method of the Program class as follows. While creating the User Entity, we have specified the UserProfile reference property.

using EFCoreCodeFirstDemo.Entities;
namespace EFCoreCodeFirstDemo
{
    internal class Program
    {
        static void Main(string[] args)
        {
            try
            {
                //Creating an Instance of the Context Class
                using EFCoreDbContext context = new EFCoreDbContext();

                //Creating an Instance of UserProfile Entity
                var userProfile = new UserProfile() { Bio = "Software Developer...."};

                //Creating User Entity, configuring the Related UserProfile Entity
                var user = new User() { Username = "Pranaya", UserProfile = userProfile };

                context.Users.Add(user);
                context.SaveChanges();
                Console.WriteLine("User and UserProfile Added");
                Console.ReadKey();
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error: {ex.Message}"); ;
            }
        }
    }
}

You can also start configuring with the UserProfile entity in the same way, as follows.

One-to-One Relationships in EF Core using Fluent API Configuration

So, modify the context class as follows:

using Microsoft.EntityFrameworkCore;
namespace EFCoreCodeFirstDemo.Entities
{
    public class EFCoreDbContext : DbContext
    {
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            //Configuring the Connection String
            optionsBuilder.UseSqlServer(@"Server=LAPTOP-6P5NK25R\SQLSERVER2022DEV;Database=EFCoreDB;Trusted_Connection=True;TrustServerCertificate=True;");
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            // Fluent API Configuration
            // Configure One to One Relationships User Person and UserProfile

            modelBuilder.Entity<UserProfile>()
                .HasOne(u => u.User) //UserProfile has one User
                .WithOne(up => up.UserProfile) //One User is associated with one UserProfile
                .HasForeignKey<User>(up => up.UserId); //Foreign key in User table

            //modelBuilder.Entity<User>()
            //    .HasOne(u => u.UserProfile) //Person has one UserProfile
            //    .WithOne(up => up.User) //One UserProfile is associated with one User
            //    .HasForeignKey<UserProfile>(up => up.UserId); //Foreign key in UserProfile table
        }

        public DbSet<User> Users { get; set; }
        public DbSet<UserProfile> UserProfiles { get; set; }
    }
}

Note: Before Proceeding further, let us delete the EFCoreDB database using SSMS and Migration folder from our project.

With the above changes in place, open the Package Manager Console and Execute the add-migration and update-database commands as follows. You can give any name to your migration. Here, I am giving EFCoreDBMig1. The name that you are giving it should not be given earlier.

One-to-One Relationships in EF Core using Fluent API Configuration

Now, if you verify the database, you should see the following.

Implementing One-to-One Relationships in EF Core using Fluent API Configuration

The choice between principal-dependent and shared primary key relationships should be based on the domain model and specific requirements of your application. The principal-dependent relationship is more common in real-world scenarios.

Note: By using the Fluent API, we have more control over the relationship configuration, such as customizing the foreign key property names, specifying cascading delete behavior, and other advanced features. Remember that the Fluent API configuration takes precedence over data annotations when both are used together.

In the next article, I will discuss How to Configure One-to-Many Relationships in Entity Framework Core using Fluent API with Examples. Here, in this article, I try to explain How to Configure the One-to-One (Required) or One-to-Zero (Optional) Relationships between Entities in Entity Framework Core Fluent API with Examples. I hope you enjoyed this Configure One-to-One Relationship using EF Core Fluent API article.

Leave a Reply

Your email address will not be published. Required fields are marked *