Nandor Krizbai
Nandor Krizbai

Reputation: 123

EF Core Fluent API: One-to-One relationship with 2 different syntax, only one is working

A one-to-one relationship is defined between 2 entities in 2 different ways, but only the one using generic methods is working. The configurations are done on the DomainVerification entity.

Given the 2 models:

public class Domain
{
    public long Id { get; set; }
}

public class DomainVerification
{
    public long Id { get; set; }
    public Domain Domain { get; set; }
}

One configuration uses a generic methods, while the other one the navigation property Domain for configuring the foreign key.

// This works
public void Configure(EntityTypeBuilder<DomainVerification> builder)
{
    builder.HasKey(d => d.Id);

    builder.HasOne<Domain>()
        .WithOne()
        .HasForeignKey<Domain>("DomainId");
}
// Produces error
public void Configure(EntityTypeBuilder<DomainVerification> builder)
{
    builder.HasKey(d => d.Id);

    builder.HasOne(d => d.Domain)
        .WithOne()
        .HasForeignKey("DomainId");
}

Trying to create the migration with the 2nd approach throws the following error:

Unable to create a 'DbContext' of type ''. The exception 'You are configuring a relationship between 'DomainVerification' and 'Domain' but have specified a foreign key on 'DomainId'. The foreign key must be defined on a type that is part of the relationship.' was thrown while attempting to create an instance.

For curiosity, if the WithOne() is changed to WithMany() in the 2nd syntax, EF Core is able to generate the migration. So far I didn't encounter a one-to-one relationship, and all of the entity configurations use the second syntax (in one-to-many relationships).

Why is the second syntax producing a migration error? It has the navigation property Domain defined in the model, so it is even visible in LINQ.

Upvotes: 0

Views: 60

Answers (1)

Yitz
Yitz

Reputation: 1306

The reason why this doesn't work for a one-to-one relationship is that EF doesn't know which entity is the primary entity and which is the dependent - so you need to use either the generic:

HasForeignKey<Domain>("DomainId")

or the non-generic:

HasForeignKey("Domain", "DomainId")

(The way this works, is that for a one-to-many, WithMany() returns a ReferenceCollectionBuilder<TRelatedEntity,TEntity>, which has a HasForeignKey(String[]) method, allowing you to just specify the columns. However, WithOne() returns a ReferenceReferenceBuilder<TEntity,TRelatedEntity>, which only has HasForeignKey methods which require a specified Entity.)

Upvotes: 1

Related Questions