Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to fix 'Unable to determine the relationship represented by navigation property' error in Entity Framework

When I try to register a user on my .NET Core 2.1 website (using identity) I get the following error:

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

The reason this happens probably has nothing to do with identity, but registering and logging in is currently the only way I know how to trigger it.

I still want the properties 'City" en 'ICollection' in my classes so I don't want to use the '[NotMapped]' attribute.

I searched on the internet and found that this is caused by a many-many relationship, I feel like this is not the case tho.

Class 'Connection':

public partial class Connection
    {
        public Connection()
        {
            ConnectionRoute = new HashSet<ConnectionRoute>();
        }

        public int Id { get; set; }
        public int StartCityId { get; set; }
        public int EndCityId { get; set; }
        public int AantalMinuten { get; set; }
        public double Prijs { get; set; }

        public Stad StartCity { get; set; }
        public Stad EndCity { get; set; }
        public ICollection<ConnectionRoute> ConnectionRoute{ get; set; }
    }

Class 'City':


public partial class City
    {
        public City()
        {
            AspNetUsers = new HashSet<AspNetUsers>();
            Hotel = new HashSet<Hotel>();
            ConnectionStartCity = new HashSet<Connection>();
            ConnectionEndCity= new HashSet<Connection>();
        }

        public int Id { get; set; }
        public string Name { get; set; }
        public string Country { get; set; }

        public ICollection<AspNetUsers> AspNetUsers { get; set; }
        public ICollection<Hotel> Hotel { get; set; }
        public ICollection<Connection> ConnectionStartCity { get; set; }
        public ICollection<Connection> ConnectionEndCity { get; set; }
    }

Class 'treinrittenContext' (dbContext) extract:

public virtual DbSet<City> City{ get; set; }

public virtual DbSet<Connection> Connection{ get; set; }

protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            ...

            modelBuilder.Entity<City>(entity =>
            {
                entity.Property(e => e.Country)
                    .IsRequired()
                    .HasMaxLength(255)
                    .IsUnicode(false);

                entity.Property(e => e.Name)
                    .IsRequired()
                    .HasMaxLength(255)
                    .IsUnicode(false);

                entity.HasMany(p => p.ConnectionStartcity)
                    .WithOne(d => d.StartCity)
                    .HasForeignKey(d => d.StartCityId);

                entity.HasMany(p => p.ConnectionEndCity)
                    .WithOne(d => d.EndCity)
                    .HasForeignKey(d => d.EndCityId);
            });

            ...

            modelBuilder.Entity<Connection>(entity =>
            {
                entity.HasOne(d => d.StartCity)
                    .WithMany(p => p.ConnectionStartCity)
                    .HasForeignKey(d => d.StartCityId)
                    .OnDelete(DeleteBehavior.ClientSetNull)
                    .HasConstraintName("FK_Verbinding_BeginStad");

                entity.HasOne(d => d.EndCity)
                    .WithMany(p => p.ConnectionEndCity)
                    .HasForeignKey(d => d.EndCityId)
                    .OnDelete(DeleteBehavior.ClientSetNull)
                    .HasConstraintName("FK_Verbinding_EindStad");
            });

            ...
        }

I expect this to work (since in my eyes it's a one-many relation), but it doesn't.

like image 480
Lukas Nys Avatar asked Apr 11 '19 09:04

Lukas Nys


People also ask

What is InverseProperty?

The InverseProperty attribute is used to denote the inverse navigation property of a relationship when the same type takes part in multiple relationships.

What is OnModelCreating in Entity Framework?

The DbContext class has a method called OnModelCreating that takes an instance of ModelBuilder as a parameter. This method is called by the framework when your context is first created to build the model and its mappings in memory.

Which Data annotation attribute is used when you have multiple relationships between the two classes?

Data Annotations - InverseProperty Attribute in EF 6 & EF Core. The InverseProperty attribute is used when two entities have more than one relationship. To understand the InverseProperty attribute, consider the following example of Course and Teacher entities.

What is not mapped in C#?

The NotMapped attribute is used to specify that an entity or property is not to be mapped to a table or column in the database. In the following example, the AuditLog class will not be mapped to a table in the database: public class Contact. {


1 Answers

UPDATE

You have multiple options here:

Option 1 with result 1

enter image description here

City Class becomes:

public partial class City
{
    public City()
    {           
        Connections = new HashSet<Connection>();
    }

    public int Id { get; set; }
    public string Name { get; set; }
    public string Country { get; set; }

    public ICollection<Connection> Connections { get; set; }
}

Connection Class becomes:

public partial class Connection
{
    public Connection()
    {
    }

    public int Id { get; set; }

    public int StartCityId { get; set; }
    public int EndCityId { get; set; }

    public int AantalMinuten { get; set; }
    public double Prijs { get; set; }     
}

Your OnModelCreating becomes:

modelBuilder.Entity<City>().HasMany(city => city.Connections)
                           .WithRequired().HasForeignKey(con => con.EndCityId);

modelBuilder.Entity<City>().HasMany(city => city.Connections)
                           .WithRequired().HasForeignKey(con => con.StartCityId);

OR you can do something like this as well wchich would be option 2 with results 2:

enter image description here

City Class becomes:

public partial class City
{
    public City()
    {           
        Connections = new HashSet<Connection>();
    }

    public int Id { get; set; }
    public string Name { get; set; }
    public string Country { get; set; }

    public ICollection<Connection> Connections { get; set; }
}

Connection Class becomes:

public partial class Connection
{
    public Connection()
    {
    }

    public int Id { get; set; }

    public virtual ICollection<City> Cities { get; set; }

    public int AantalMinuten { get; set; }
    public double Prijs { get; set; }     
}

And you don't have to do anything in your OnModelCreating.

like image 168
Dimitri Avatar answered Sep 18 '22 15:09

Dimitri