mrmowji
mrmowji

Reputation: 944

EF Core one-to-many relationship beside another foreign key property

I have these two models (irrelevant properties are not present):

// based on Identity
public class User {
  public long? CityId { get; set; }
  public virtual City City { get; set; }
}

public class City : Base {
}

public class Base {
  public string CreatorId { get; set; }
  public virtual User Creator { get; set; }
}

Now, the problem is that EF Core can't determine the one-to-many relationship between User and City and it thinks that there's a one-to-one relationship (I remember I hadn't such problem with EF 6).

The child/dependent side could not be determined for the one-to-one relationship between 'User.City' and 'City.Creator'. To identify the child/dependent side of the relationship, configure the foreign key property. If these navigations should not be part of the same relationship configure them without specifying the inverse.

So, I'm forced to add another navigation property to City:

public class City : Base {
  public virtual IList<User> Users { get; set; }
}

But the problem persists:

Unable to determine the relationship represented by navigation property 'City.Users' of type 'IList'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.

I ended up using Fluent API and ModelBuilder.

modelBuilder.Entity<User>()
            .HasOne<City>(u => u.City)
            .WithMany(c => c.Users)
            .HasForeignKey(u => u.CityId);

Using Fluent API, we can remove that Users navigation property inside City and call an empty WithMany (see the first comment):

modelBuilder.Entity<User>()
            .HasOne<City>(u => u.City)
            .WithMany()
            .HasForeignKey(u => u.CityId);

Is it the only way? Am I doing something wrong?

Edit: I had more properties like CreatorId (for example LastEditorId) on the Base class in the EF 6 version, and it still could figure out the relationships. Tried this in the EF Core version. Not working.

Upvotes: 0

Views: 3107

Answers (1)

Xueli Chen
Xueli Chen

Reputation: 12685

The problem seems to be that the City that inherits from the Base model contains all the properties of the parent class, so that the relationship between City and User is one-to-one, not one-to-many.

In fact , Entity Framework Core follows the same convention as Entity Framework 6.x conventions for one-to-many relationship. The only difference is that EF Core creates a foreign key column with the same name as navigation property name and not as <NavigationPropertyName>_<PrimaryKeyPropertyName>.

Fluent API specify the model configuration that you can with data annotations as well as some additional functionality that can not be possible with data annotations.

  • In Entity Framework Core, the ModelBuilder class acts as a Fluent API.

  • We can configure many different things by using it because it provides more configuration options than data annotation attributes.

  • Data annotations and the fluent API can be used together, but precedence of Fluent API > data annotations > default conventions.

You could refer to the links below to help you better understand Fluent Api :

https://www.entityframeworktutorial.net/efcore/fluent-api-in-entity-framework-core.aspx

https://entityframeworkcore.com/model-fluent-api

Upvotes: 1

Related Questions