Search code examples
c#entity-frameworkinheritanceef-code-firstcode-first

C# Entity Framework Code First Abstract Inheritance


In the following classes I am trying to do a code first setup using abstract base classes. Sorry if this is a duplicate question. I did try to search the site and google for an answer but nothing I have tried has worked.

public abstract class IDObject
{
    [Key]
    public Int32 ID { get; internal set; }
}

public abstract class NamedObject : IDObject
{
    public String Name { get; set; }
}

public abstract class HWObject : NamedObject
{
    public Double Free { get; set; }
    public Double Max { get; set; }
    public Double Used { get; set; }
}

public abstract class CPUObject : HWObject { }
public abstract class MemoryObject : HWObject { }
public abstract class StorageObject : HWObject { }

public class Server : NamedObject
{
    [JsonConstructor]
    internal Server() { }
    public String CompanyName { get; set; }
    public Boolean IsRunning { get; set; }
    public CPUObject CPU { get; set; }
    public MemoryObject Memory { get; set; }
    public StorageObject Storage { get; set; }
}

I have the following DBContext:

public class DataContext : DbContext
{
    public DataContext() : base("name=DataContext") { }

    public DbSet<Server> Servers { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
    }
}

When I try to view the Read-Only Data Model I get the following error:

System.InvalidOperationException: The abstract type 'MyApp.CPUObject' has no mapped descendants and so cannot be mapped. Either remove 'MyApp.CPUObject' from the model or add one or more types deriving from 'MyApp.CPUObject' to the model.

How do I change the DBContext so the error goes away?

EDIT: According to the answer below I have removed abstract from the CPUObject, MemoryObject and StorageObject as they should have never been abstract.

I have changed the DBContext to the following: (The mappings create a 1 to 1 relationship)

public class DataContext : DbContext
{
    public DataContext() : base("name=DataContext") { }

    public DbSet<Server> Servers { get; set; }

    public DbSet<CPUObject> CPUObjects { get; set; }
    public DbSet<MemoryObject> MemoryObjects { get; set; }
    public DbSet<StorageObject> StorageObjects { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Server>().HasRequired(u => u.CPU).WithRequiredDependent().Map(m => m.MapKey("CPUID"));
        modelBuilder.Entity<Server>().HasRequired(u => u.Memory).WithRequiredDependent().Map(m => m.MapKey("MemoryID"));
        modelBuilder.Entity<Server>().HasRequired(u => u.Storage).WithRequiredDependent().Map(m => m.MapKey("StorageID"));
    }
}

Solution

  • CPUObject is currently an abstract class, which cannot be instantiated. Just remove the abstract to make it a concrete object. Then, add public DbSet<CPUObject> CPUs { get; set; } to your DBContext

    You are currently getting the error because EF is looking for a concrete class, so the error says you can make another concrete class that inherits (i.e. 'deriving from') CPUObject