Let's start with one-to-many relationship:
public sealed class MyContext : DbContext
{
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<Slave>()
.HasOne(typeof(Master))
.WithMany() // *
.HasForeignKey(nameof(Slave.ForeignField));
}
}
So I declare that per one record in Master table I can have multiple records in Slave table. When I run EF tools to build migration this is accepted and works fine.
But when I change the line marked with asterisk to:
.WithOne()
in order to build one-to-one relationship building migration fails with error:
You are configuring a relationship between 'Slave' and 'Master' but have specified a foreign key on 'ForeignField'. The foreign key must be defined on a type that is part of the relationship.
I don't get it, just a second ago the given field (property in C# terms) was OK, and now EF claims it cannot find it?
Whad do I miss? How to make EF happy?
Record types are as follows -- please note there are no navigational properties.
internal sealed class Slave
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public Guid InstanceId { get; set; }
public Guid ForeignField { get; set; }
}
internal sealed class Master
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public Guid Id { get; set; }
}
For the time being I solved this using raw SQL, it works, but I am still curious what is wrong here.
Thanks to @AminGolmahalle answer, my curiosity was triggered why and can I use HasForeignKey
in generic form. This lead me to finding out that I cannot, but what more is that WithOne
and WithMany
are not 1:1 replacements of each other. Both lead to different overloads.
So the first version one-to-many worked because I was hitting the right overload, the second didn't, because I was passing incorrect arguments. The correct version is:
builder.Entity<Slave>()
.HasOne(typeof(Master))
.WithOne()
.HasForeignKey(nameof(Slave), nameof(Slave.ForeignField)); // changed
the first argument has to be name of the slave table (again).
But is is even better to switch to generic version (see last comment under accepted answer) and avoid possibility of such "stupid" mistake in the first place.