Reputation: 85
I have been playing around with .NET Core for the past couple of weeks and decided to try EF Core (coming from ASP.NET MVC with NHibernate). After a bit of digging I found a nice extensions called EF Visual Designer. It allows me to visually create the model and generate code.
I have defined a simple one-to-one relationship shown in the diagram: Simple one-to-one relationship
After generating the code I get the following as Fluent API code:
modelBuilder.Entity<Authentication>()
.ToTable("Authentications")
.HasKey(t => t.Id);
modelBuilder.Entity<Authentication>()
.Property(t => t.Id)
.IsRequired()
.ValueGeneratedOnAdd();
modelBuilder.Entity<User>()
.ToTable("Users")
.HasKey(t => t.Id);
modelBuilder.Entity<User>()
.Property(t => t.Id)
.IsRequired()
.ValueGeneratedOnAdd();
modelBuilder.Entity<User>()
.HasOne(x => x.Authentication)
.WithOne()
.HasForeignKey("Authentication_Id")
.IsRequired();
The user class has the following (relevant) properties:
public Class User {
[Key]
[Required]
public Guid Id { get; set; }
...
public virtual Authentication Authentication { get; set; }
}
Authentication has the following (relevant) property:
public class Authentication {
[Key]
[Required]
public Guid Id { get; set; }
}
However when I try to generate a migration I get the following error:
You are configuring a relationship between 'User' and 'Authentication' but have specified a foreign key on 'Authentication_Id'. The foreign key must be defined on a type that is part of the relationship.
I tried switching to a many-to-one relationship and that works without any problems. That could be a work-around but not a very clean one. Is this perhaps due to naming issues like both entities having "Id" as primary key?
If that's the case, what is the "best practice"? Do I give every entity a unique ID-column name? How do I go about an abstract entity with derived classes all inheriting the ID column?
Upvotes: 6
Views: 13525
Reputation: 67
All who have responded thus far are right. You were missing a foreign key in your dependent entity, so you need to add one. According to your code, it has to be "Authentication_Id" as that is the name that you referenced -- yet you had not actually declared one!
Secondly, Vladislav Vazhenin is right:
Got an error when tried to build on .HasForeignKey(x => x.AuthenticationId); But .HasForeignKey <User> (x => x.AuthenticationId); worked for me
Just make sure that you point to the navigation properties and not the associated entity key properties (Authentication vs AuthenticationId). So, consider that.
In fact, someone needs to push for the documentation (which seems to be user edited) to include these subtle differences. For example; .HasOne also has a variation of
.HasOne(x=>x.Authentication)
and
.HasOne<Authentication>()
Include, a note on if they differ by the versions of Entity Framework Core. The compiler sometimes blocks and or ignores some of these nice to haves or deprecated command variations. But we need to know which will work for which version and how the overriding of data annotations by fluent api works (put emphasis on which one takes precedence).
Upvotes: 0
Reputation: 21476
I have never used EF Visual Designer to generate codes but just by looking at your code, either the User
entity needs the foreign key of Authentication
, or Authentication
entity needs the foreign key of User
.
Let's say you want to put the foreign key in User
:
public class User
{
[Key]
[Required]
public Guid Id { get; set; }
public Guid AuthenticationId { get; set; }
// Even this navigation property is optional
// for configuring one-to-one relationship
public virtual Authentication Authentication { get; set; }
}
public class Authentication
{
[Key]
[Required]
public Guid Id { get; set; }
}
Then the one-to-one relationship should be configured as:
modelBuilder.Entity<User>()
.HasOne(x => x.Authentication)
// Or like this if you don't have Authentication navigation property:
//.HasOne<Authentication>()
.WithOne()
.HasForeignKey(x => x.AuthenticationId);
And no, you don't have to give every entity a unique ID-column name. In fact, you can call whatever in your code and rename it inside the configuration:
modelBuilder.Entity<User>()
.Property(x => x.Id).HasColumnName("WHATEVER_YOU_WANT_TO_CALL_IN_DB");
Upvotes: 8
Reputation: 21194
You need to put the foreign key on the other class. It looks like you don't have a property "Authentication_Id" on the Authentication class.
Upvotes: 0