How to configure one-to-one relationship in EF Core with FK on both ends

766 Views Asked by At

I have following entities:

public class Subscription
{
    public int Id { get; set; }

    public int? BillingContractId { get; set; }
    public BillingContract BillingContract { get; set; }

    //other properties
}

public class BillingContract 
{
    public int Id { get; set; }

    public int SubscriptionId { get; set; }
    public Subscription Subscription { get; set; }

    //other properties
}

So each subscription might have only one billing contract and each billing contract belongs to a single subscription.

I'm trying to configure this relationship in my dbcontext:

builder.Entity<Subscription>()
    .HasOne(subscription => subscription.BillingContract)
    .WithOne(billingContract => billingContract.Subscription)
    .HasForeignKey<BillingContract>(billingContract => billingContract.SubscriptionId)
    .IsRequired(true);

builder.Entity<BillingContract>()
    .HasOne(billingContract => billingContract.Subscription)
    .WithOne(subscription => subscription.BillingContract)
    .HasForeignKey<Subscription>(subscription => subscription.BillingContractId)
    .IsRequired(false);

But from the generated migration(or from the snapshot or from the actual DB schema) I can tell that only FK in Subscription table is created. I cannot make EF to create a FK(and index) in the BillingContract table. I also tried to use annotation attributes with the same result.

Did I miss something? Or it's a bug in EF?

I'm using EF Core 2.2

To eliminate a possibility of a corrupted db snapshot I created a brand new console project using EF Core 3.1. After adding initial migration I have the same result with missing FK:

protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.CreateTable(
        name: "BillingContracts",
        columns: table => new
        {
            Id = table.Column<int>(nullable: false)
                .Annotation("SqlServer:Identity", "1, 1"),
            SubscriptionId = table.Column<int>(nullable: false)
        },
        constraints: table =>
        {
            table.PrimaryKey("PK_BillingContracts", x => x.Id);
        });

    migrationBuilder.CreateTable(
        name: "Subscriptions",
        columns: table => new
        {
            Id = table.Column<int>(nullable: false)
                .Annotation("SqlServer:Identity", "1, 1"),
            BillingContractId = table.Column<int>(nullable: true)
        },
        constraints: table =>
        {
            table.PrimaryKey("PK_Subscriptions", x => x.Id);
            table.ForeignKey(
                name: "FK_Subscriptions_BillingContracts_BillingContractId",
                column: x => x.BillingContractId,
                principalTable: "BillingContracts",
                principalColumn: "Id",
                onDelete: ReferentialAction.Restrict);
        });

    migrationBuilder.CreateIndex(
        name: "IX_Subscriptions_BillingContractId",
        table: "Subscriptions",
        column: "BillingContractId",
        unique: true,
        filter: "[BillingContractId] IS NOT NULL");
}
1

There are 1 best solutions below

1
Karney. On

This is not an EF bug. Usually, two tables have an association relationship, and you only need to create one foreign key in one of the tables. The two-way foreign key is for the entity and does not exist in the database design. This docuement has give the detail example.