There are multiple navigations in entity type EF Migration

Viewed 598

I am currently making an EF migration script, on a schema model that looks like this

public class Schema : RootId
{
   public int Version { get; set; }

   [ForeignKey("entity_id")]
   public virtual ICollection<Entity> Entities { get; set; } = null!;

   [ForeignKey("entity_id")]
   public virtual ICollection<Entity> Relations { get; set; } = null!;
}

Here both relations uses the same object type, and when I do an migration I get the error

There are multiple navigations in entity type 'Schema' which are pointing to same set of properties using a [ForeignKey] attribute: 'entity_id'

which is true as the foreign key for both of them is entity_id. but this has worked before, but back then the type was ICollection<Relation>, which was a complete copy of the Entity, which does not make sense, since this introduces code duplication.

How do I convert Relations to an ICollection<Entity> and still be able to use the foreing_key entity_id - what i don't get is how changing the type make it confused?

Update:

Ok, i tried doing it like this then

public class Schema : RootId
{
   public int Version { get; set; }

   [ForeignKey("entity_id")]
   public virtual ICollection<Entity> Entities { get; set; } = null!;

   [ForeignKey("entity_id")]
   public virtual ICollection<Relation> Relations { get; set; } = null!;
}



public class Entity : BaseEntity
{
} 

public class Relation : BaseEntity
{
} 


public class BaseEntity : RootId
{
} 

but this then causes and foreign key violation, everytime I insert or update the table?...

"Key (attribute_entity_id)=(4) is not present in table \"relation\"."
3 Answers

You can fix it with a little change in your models. Just define the different foreign keys for both Entities and Relations collections.

public class Schema
{
    public int Id { get; set; }

    public int Version { get; set; }

    public virtual ICollection<Entity> Entities { get; set; } = null!;

    public virtual ICollection<Entity> Relations { get; set; } = null!;
}

public class Entity
{
    public int Id { get; set; }

    public int SchemaAsEntityId { get; set; }
    [ForeignKey("SchemaAsEntityId")]
    public Schema SchemaAsEntity { get; set; }

    public int SchemaAsRelationId { get; set; }
    [ForeignKey("SchemaAsRelationId")]
    public Schema SchemaAsRelation { get; set; }
}

And because an entity making multiple foreign keys with another model at the same time, you need these configs in your OnModelCreating:

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

    modelBuilder.Entity<Schema>().HasMany(x => x.Entities).WithOne(x => x.SchemaAsEntity)
                .HasForeignKey(x => x.SchemaAsEntityId).IsRequired().OnDelete(DeleteBehavior.ClientSetNull);

    modelBuilder.Entity<Schema>().HasMany(x => x.Relations).WithOne(x => x.SchemaAsRelation)
                .HasForeignKey(x => x.SchemaAsRelationId).IsRequired().OnDelete(DeleteBehavior.ClientSetNull);
}

Your actual data model looks like not working, imagine this: If you fetch data from the "Schema" table, including the linked "Entity" objects, EF Core would not be able to tell if an "Entity" must go in the Entites collection or in the Relation collection.

You said though that "this" was actually working before:

this has worked before, but back then the type was ICollection, which was a complete copy of the Entity, which does not make sense, since this introduces code duplication.

If that is the case I would keep the "Relation" object/table. To avoid code duplication you could simply use inheritance

class Relation : Entity {}

This implies a Relation table and an Entity table but no code duplication.

... I have seen your edit, i cannot comment, though to better understand your new issue, can you show the query executed?

What you are basically trying to acomplish here is saying to entity class that it needs to have 2 of the same foreign keys. When you add [ForeignKey] attribute to a collection like this that means that you want to create foreign key on your destination table in this case that table is entity, and entity can't have two foreign keys with the same name. Why would you want to have same foreign key for two different relationships? There is not enough context for me to help you directly but you could try and make 2 different foreign keys one for each reltionship. For example:

public class Schema : RootId
{
   public int Version { get; set; }

   [ForeignKey("schema_Id")]
   public virtual ICollection<Entity> Entities { get; set; } = null!;

   [ForeignKey("schema_Id")]
   public virtual ICollection<Relation> Relations { get; set; } = null!;
}

I think this would solve your issue

Related