efcore icon indicating copy to clipboard operation
efcore copied to clipboard

Exclude only base type table from Migrations

Open ajcvickers opened this issue 2 years ago • 2 comments

Originally filed as https://github.com/dotnet/efcore/issues/2725#issuecomment-1382199920 by VeMike

So how would I ignore just a base class, but not a derived class using this approach?

Consider the following model:

[Table(nameof(Human))]
public class Human
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int HumanId { get; set; }
    
    public int Age { get; set; }
}

[Table(nameof(Developer))]
public class Developer : Human
{
    public string MainLanguage { get; set; }
}

The database context for this model is the following

public class FooContext : DbContext
{
    public DbSet<Developer> Developers { get; set; } = null!;

    /// <inheritdoc />
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        // This is made to get TPT
        modelBuilder.Entity<Human>().ToTable(nameof(Human));
        modelBuilder.Entity<Developer>().ToTable(nameof(Developer));
        
        modelBuilder.Entity<Human>().ToTable(nameof(Human), t => t.ExcludeFromMigrations());
    }

    /// <inheritdoc />
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        base.OnConfiguring(optionsBuilder);

        optionsBuilder.UseSqlServer("<FooBarConnectionString>");
    }
}

As you can see I only want Developer to be in the migration. Human should be excluded. Why would I want to do this? I am extending an existing model and the base (Human) already exists in the database. I want to add Developer to this existing model.

But if I create a migration the whole hierarchy of Human is excluded (basically all classes of type Human). But I want the Developer to be created.

Of course, I could just remove the line

modelBuilder.Entity<Human>().ToTable(nameof(Human), t => t.ExcludeFromMigrations());

and then manually remove the added Human from the migration. But is there a way to do this automatically?

ajcvickers avatar Jan 17 '23 12:01 ajcvickers

Note to implementor:

Add TPC condition to: https://github.com/dotnet/efcore/blob/03bb7b7090f2077db45d11afa2c5d94d92d49296/src/EFCore.Relational/Extensions/RelationalEntityTypeExtensions.cs#L1455-L1458

Also check that the dependent is mapped to the same table in: https://github.com/dotnet/efcore/blob/03bb7b7090f2077db45d11afa2c5d94d92d49296/src/EFCore.Relational/Extensions/RelationalEntityTypeExtensions.cs#L1461-L1465

Change to ||: https://github.com/dotnet/efcore/blob/03bb7b7090f2077db45d11afa2c5d94d92d49296/src/EFCore.Relational/Migrations/Internal/MigrationsModelDiffer.cs#L560-L561

Check IsExcludedFromMigrations in: https://github.com/dotnet/efcore/blob/03bb7b7090f2077db45d11afa2c5d94d92d49296/src/EFCore.Relational/Migrations/Internal/MigrationsModelDiffer.cs#L2201-L2202

AndriySvyryd avatar Jan 18 '23 02:01 AndriySvyryd

Note from triage: this is a bug, but fix should be documented as a breaking change since TPT cases where all tables were excluded will now only exclude the base table.

ajcvickers avatar Jan 19 '23 14:01 ajcvickers