Search code examples
c#inheritanceentity-framework-coreef-code-first

Inheriting properties from model - Navigation properties can only participate in a single relationship


I'm trying to share common properties with multiple entities by using multiple levels of inheritance, but I'm running into an error.

Cannot create a relationship between 'User.SupersCreated' and 'Super.CreatedBy' because a relationship already exists between 'User.BasicsCreated' and 'Basic.CreatedBy'. Navigation properties can only participate in a single relationship. If you want to override an existing relationship call 'Ignore' on the navigation 'Super.CreatedBy' first in 'OnModelCreating'.

The structure of my models is as follows.

public class EntityBase
{
    public Guid Id { get; set; }
    public Guid CreatedById { get; set; }
    public User CreatedBy { get; set; }
}

public class Basic: EntityBase
{
    public string BasicProperty { get; set; }
}

public class Super : Basic
{
    public string SuperProperty { get; set; }
}

public class User : IdentityUser<Guid>
{
    public ICollection<Basic> BasicsCreated { get; set; }
    public ICollection<Super> SupersCreated { get; set; }
}

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

    modelBuilder.Entity<User>()
        .HasMany(x => x.BasicsCreated)
        .WithOne(x => x.CreatedBy);

    modelBuilder.Entity<User>()
        .HasMany(x => x.SupersCreated)
        .WithOne(x => x.CreatedBy);
}

The problem seems to be a result of Super Inheriting from Basic, or at least, the problem goes away when I remove this level of inheritance and make Super inherit from EntityBase (however than I'll lose the properties that exist in Basic).

Can anyone please help me understand why I'm getting this error and what should be done to fix it?


Edit

After considering this some more, I think I'm trying to abuse inheritance to do what it's not intended to do.

The database structure I was hoping to end up with, is: enter image description here

Even though my Basic and Super tables share the same properties, with Super having it's own additional properties, there's no relationship between Basic data and Super data.

From having a look at Microsoft's tutorial on implementing inheritance, there's two options:

  • Table per type
  • Table per hierarchy

Neither of these are what I'm trying to achieve.

Perhaps I should be using interfaces to define the common properties that exist between unrelated entities. It seems like I need to back and re-evaluate my design anyway.


Solution

  • If some of the base classes of the entity is identified as entity (as with your Super and Basic), by default EF Core will try to use one of the database inheritance strategies.

    If you don't want that (want to treat is just like non entity base class), then you have to configure that explicitly at the very beginning of the OnModelCreating, e.g. for your sample

    modelBuilder.Entity<Super>().HasBaseType((Type)null);
    

    or more generally using a loop similar to this

    foreach (var entityType in modelBuilder.Model.GetEntityTypes())
        entityType.BaseType = null;
    

    and then define explicitly the entity hierarchy if and where needed.