Search code examples
c#entity-framework-core

Entity Framework Core: How to dynamically get the DbSet from a derived Type?


I have the following abstract class, named Sector:

public abstract class Sector
{
    public string ID {get; set;}
    public string Name {get; set;}
    public Sector(){}
 }

And a second class, GICSSector, which inherits from Sector:

public class GICSSector: Sector
{
   public virtual ICollection<GICSIndustryGroup> IndustryGroups {get; set;}
}

I have the following DbSet in my DbContext:

public DbSet<GICSSector> GICSSectors {get; set;}

I am trying to write a generic method to loads data from a CSV file, create the objects on the fly and then store the objects in my SQLLite database:

public static void UpdateEntitiesFromCSV<T>(MyContextFactory factory, string fileName) where T : class
{
    var entities = new List<T>();
    
    // ... Load entities from the CSV
    // ... Create the objects and add them to the list

    // Add the objects to the database

    using (var db = factory.Create(new DbContextFactoryOptions()))
    {
         var set = db.Set<T>();
                
         foreach(T e in entities)
         {
             set.Add(e);
         }
                
         db.SaveChanges();
    }

}

I use the fluent API to manage the tables:

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

    // GICSSector    
    modelBuilder.Entity<GICSSector>().HasKey(s => new { s.ID }); 
    modelBuilder.Entity<GICSSector>().Property(s => s.ID).HasMaxLength(2);      
    modelBuilder.Entity<GICSSector>().Property(s => s.Name).IsRequired();     
    modelBuilder.Entity<GICSSector>().Property(s => s.Name).HasMaxLength(50);
}

If I run the code I get the following exception:

SQLite Error 1: 'no such table: Sectors'.

If I check the type with typeof(T) or using myEntity.GetType() I get the same expected result: MyNamespace.GICSSector

Why EF Core wants to store it in a table called "Sectors" (the base type) and not in the expected GICSSectors?

How can I fix it?

Note: The method is a generic one that won't be used to handle only classes that inherit from Sector.


Solution

  • Tell EF explicitly what table to use:

    [Table("GICSSectors")]
    public class GICSSector: Sector
    {
        public virtual ICollection<GICSIndustryGroup> IndustryGroups {get; set;}
    }
    

    or use fluent api:

    modelBuilder.Entity<GICSSector>().ToTable("GICSSectors");