Entity Framework Core: Foreign key linked with a non-primary key

How can we establish a one-to-one relationship between two models, if we do not want to use the primary key to link the foreign key?

That is, suppose we have the following models:

public class Menu
{
  [Key]
  public int Id { get; set; }
  public string MenuCode { get; set; }
  public Route Route { get; set; }
}

public class Route
{
  [Key]
  public int Id { get; set; }
  public string MenuCode { get; set; }
  public string Name { get; set; }
  public Menu Menu { get; set; }
}

We want to establish the one-to-one relationship between them, however, we want the foreign key of Route “MenuCode” to be linked to the “MenuCode” field of the Menu class.

If we try to do the following using the Fluent API in the data context:

modelBuilder.Entity<Menu>()
.HasOne(x => x.Route)
.WithOne(x => x.Menu)
.HasForeignKey<Route>(x => x.MenuCode);

We’ll get the following error:

The relationship from ‘Menu.Route’ to ‘Route.Menu’ with foreign key properties {‘MenuCode’ : string} cannot target the primary key {‘Id’ : int} because it is not compatible. Configure a principal key or a set of compatible foreign key properties for this relationship.

This error occurs because you are trying to link MenuCode of the class Route with Id of the class Menu. The problem is that MenuCode is a string and Id is an integer, therefore, they are not compatible. What we want is to link MenuCode of Route with MenuCode of Menu.

The solution is to configure the PrincipalKey. The PrincipalKey will allow us to define the reference key with a unique restriction which will be the destination of the relationship. That is to say, with the PrincipalKey we can say that we want to link our foreign key MenuCode of the class Route, with the field MenuCode of the class Menu.

We emphasize that the reference column of the other table must have unique values, that is, it must have a unique constraint. The unique constraint means that values cannot be repeated in different entries in a column. Once we configure a field as PrincipalKey, the unique constraint will automatically be applied.

We can configure the PrincipalKey in the following manner:

modelBuilder.Entity<Menu>()
.HasOne(x => x.Route)
.WithOne(x => x.Menu)
.HasPrincipalKey<Menu>(x => x.MenuCode)
.HasForeignKey<Route>(x => x.MenuCode);

Now with this, we are marking MenuCode of the Menu class as the principal key, which means that it will be the destiny of the one-to-one relationship, in other words, the link will be made between the Route’s MenuCode and the Menu’s MenuCode. From here we can add our migrations and proceed with the development of our application.

Summary

  • With Entity Framework Core we can define relationships between our models
  • We can use HasPrincipalKey to define with which field we want to link our foreign key

Courses

If you want to learn more, check out my Udemy courses today. The following links have a discount code applied:

  1. Building Applications with React 17 and ASP.NET Core 6: https://www.udemy.com/course/building-applications-with-react-and-aspnet-core/?couponCode=SEPTEMBER2021
  2. Building Applications with Angular 11 and ASP.NET Core 5: https://www.udemy.com/course/building-applications-with-angular-and-aspnet-core/?couponCode=SEPTEMBER2021
  3. Programming in Blazor – ASP.NET Core 5: https://www.udemy.com/course/programming-in-blazor-aspnet-core/?couponCode=SEPTEMBER2021
  4. Building RESTful Web APIs with ASP.NET Core 3.1: https://www.udemy.com/course/building-restful-web-apis-with-aspnet-core/?couponCode=SEPTEMBER2021
  5. Introduction to Concurrency in C# – Async and Paralellism: https://www.udemy.com/course/introduction-to-concurrency-in-c-async-and-paralellism/?couponCode=SEPTEMBER2021

Kind regards!

2 comments

Leave a comment