13
votes

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.

1
You should think about your naming as well, collections should be plurial (meervoud) you DbSets for example should be Connections & Cities as well as your properties ConnectionStartCity & ConnectionEndCity. As for the error, could be because you are missing the [Required] Annotation on your StartCity & EndCity.Dimitri
@Dimitri, thank you for the tip on naming conventions. Adding [Required] annotations to StartCity and EndCity in Connection did not solve it.Lukas Nys

1 Answers

14
votes

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.