dotnet / efcore

EF Core is a modern object-database mapper for .NET. It supports LINQ queries, change tracking, updates, and schema migrations.
https://docs.microsoft.com/ef/
MIT License
13.73k stars 3.17k forks source link

Ability to exclude/skip/ignore parts of the model from migrations so that a table is not created (for overlapping bounded contexts) #2725

Closed brent-russell closed 4 years ago

brent-russell commented 9 years ago

I suggest having an attribute that can be applied to DbSet properties in a DbContext, which indicates whether or not to include them in the migration scaffolding process.

An example use case is when part of an application's database is replicated from another environment. Replicated entities will be included in the same DbContext as custom-developed entities so they can be queried. During development many migrations may be performed. Each time a migration is scaffolded, the replicated entities will be added to the migration, and then must be removed manually.

If an attribute only used for EF commands is too polluting to include in the DbContext, some alternatives might be: an additional config file that can be specified on the command line listing which entities should be excluded. Or perhaps additional command line arguments that allow a migration to be generated for specified entities only instead of scanning and comparing all entities.

Also consider the scenario of inherited models when looking at this feature https://github.com/aspnet/EntityFramework/issues/5572

rowanmiller commented 9 years ago

Agreed that this would be good to enable. Generalized the title a bit as an attribute may or may not be the best way to do this. An attribute may be good sugar over a more powerful hook to exclude parts of the model.

Moving to backlog as we will look at this after the first stable release.

wwarby commented 8 years ago

+1, this to would be extremely useful.

maleet commented 8 years ago

+1

ownakas1mon commented 8 years ago

+1

soeron commented 8 years ago

+1 any status on this item?

neridonk commented 7 years ago

+1 any status on this item?

rowanmiller commented 7 years ago

No updates. We want to do it, but there are several items higher than it on the backlog.

omayhemo commented 7 years ago

Those items listed as higher on the backlog have now been closed. When can we expect inclusion to a sprint?

rowanmiller commented 7 years ago

The main features we talk about being higher priority are the ones listed here https://docs.microsoft.com/en-us/ef/efcore-and-ef6/features. There is still quite a list of them that have not been implemented.

thiennn commented 7 years ago

I just found a workaround

  1. Create another DbContext that inherit your DbContext, for example MigrationDbContext. Override the OnModelCreating method and ingore entities that you want it's table not being generated.
 protected override void OnModelCreating(ModelBuilder builder)
 {
     base.OnModelCreating(builder);
     builder.Ignore<Category>();
 }
  1. Create another class that implement IDbContextFactory. For example
    public class MigrationContextFactory : IDbContextFactory<MigrationDbContext>
    {
        public MigrationDbContext Create()
        {
            var optionsBuilder = new DbContextOptionsBuilder<MigrationDbContext>();
            optionsBuilder.UseSqlite("Data Source=blog.db");

            return new MigrationDbContext(optionsBuilder.Options);
        }
    }

The migration tool will discover this MigrationContextFactory and use the MigrationDbContext.

Oskarsson commented 7 years ago

+1, This would make it possible to use ef core in plugin based architectures with each context inheriting from the core context with working relationships between contexts.

Mucaccino commented 7 years ago

+1

soeron commented 7 years ago

+1

ganagus commented 6 years ago

+100

ctrlaltdan commented 6 years ago

+1

rindybo commented 6 years ago

Hope quickly,thank you

Tarig0 commented 6 years ago

To add to this, It would be nice to be able to add IgnoreBase or OnlyDeclared type options.

Though I think you would have to do something like ModelB.Except(ModelA)

There would be some very interesting cases such as when HasValue<> is used on a base entity

Tarig0 commented 6 years ago

Also If this goes into design, There should be a "depends on" migration attribute added to ensure that the tables that are required for the derived DBContext is in place

This could be implemented as either

  1. Must have migration A from dbcontext B
  2. Tables A, B must exists with columns A.A, A.B, B.A, B.B ect.
Biarity commented 6 years ago

+1 bump

lambidu commented 6 years ago

+100500

Hazzamanic commented 6 years ago

+1

junyuanz123 commented 6 years ago

+1

junyuanz123 commented 6 years ago

I am wondering does this means if I have IdentityDbContext & DbContext, and ApplicationUser (which is part of the IdentityDbContext & also part of the DbContext) will be created twice?

Right now I have 2 different contexts:

public class ApplicationDbContext: DbContext
    {
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options): base(options)
        {
        }

        public DbSet<Course> Courses { get; set; }

        public DbSet<Enrollment> Enrollments { get; set; }

        public DbSet<Domain> Domains { get; set; }
    }
    public class ApplicationIdentityDbContext: IdentityDbContext<ApplicationUser>
    {
        public ApplicationIdentityDbContext(DbContextOptions<ApplicationIdentityDbContext> options): base(options)
        {
        }
    }

However, what I am trying to do is put those 2 contexts into 2 databases. However, when I use ApplicationIdentityDbContext for migration it will create all table in one database. If I use ApplicationDbContext it will only create Courses & Enrollments, Domains & ApplicationUser tables.

Any idea how I can solve this issue?

nprieto95 commented 6 years ago

Since no one made it explicit apart from the title on the “overlapping bounded contexts”, I add that this would be nice to have when working with DDD (Domain-Driven Design) so that beginners on that subject like me can find this more easily next time when searching for the term DDD.

arnvanhoutte commented 6 years ago

Any update about this?

bricelam commented 6 years ago

@arnvanhoutte:


divega modified the milestones: Backlog, 3.0.0 27 days ago

It's planned for version 3.0.0

alexsandro-xpt commented 5 years ago

+1 It will be useful for work within mixed fixed tables and migration tables making migration genered table working together.

btodts commented 5 years ago

+1, definitely

MaklaCof commented 5 years ago

Also very useful when database model is shared with another application, which handles migrations for some entities, but not all.

bricelam commented 5 years ago

Note to implementer: Update the obsolete ToView method to call this in order to preserve its old semantics.

cmorgan091 commented 5 years ago

+1 this is key to DDD that implement a common context where there is a need for referential integrity from other contexts (multi-tenant or references to users or other common elements)

In EF6 we could hack this by implementing a CSharpMigrationCodeGenerator which overrode Generate commands to check the schema name and just return. Have attempted this with a MigrationsModelDiffer in EF Core, please see my next post which links to an example of what I have done to implement this

cmorgan091 commented 5 years ago

For anybody that is interested, I have implemented a workaround that I believe allows this to work when the elements you want to exclude are part of a different schema in the database (which is what I wanted to do).

I have included this as an example in an issue I have raised here: https://github.com/aspnet/EntityFrameworkCore/issues/15828

Let me know if this helps anyone

ajcvickers commented 5 years ago

Consider also the case of excluding FKs from the database: #15854

ajcvickers commented 5 years ago

Proposing punt...

echuck66 commented 5 years ago

I see that another reported issue was marked as a duplicate of this one...

https://github.com/aspnet/EntityFrameworkCore/issues/14283

I'm not seeing how this is a duplicate of that issue, and was wondering if any progress had been made or fix found for the issue of subsequent migrations attempting to re-create tables that have already been created in previous migrations. It's like instead of attempting an 'ALTER TABLE' process, the software punts and decides to just re-create the table. This is NOT a good thing.

If I recall correctly, last year things were not so messed up with EF Core and related technologies. Today, there seems to be a lot of packages incompatible with newer ones (to be expected to some degree), but I'm also finding newer packages and technologies are not working as they should. Case in point: MySql package for EF Core has no default mechanism to convert bit to boolean. This is very basic stuff.

Anyway, enough of my rant... is there a fix to prevent ef core migrations from attempting to re-create tables that already exist?

I'm really hoping this is just some configuration switch or migration setting I missed or something and not standard behavior for a product like ef core.

ajcvickers commented 5 years ago

@echuck66 It sounds like your issue is different to the feature that is being tracked here. Can you please file a new issue and include a small, runnable project/solution or complete code listing that demonstrates the behavior you are seeing.

echuck66 commented 5 years ago

...disregard. I think I figured out what's going on... ef core is tracking updates to the schema in the project snapshot file. It was missing.

ajcvickers commented 4 years ago

Also consider an attribute for at least some of this. (If it doesn't get done with the fluent API, then create a new issue for it.) See https://github.com/aspnet/EntityFrameworkCore/issues/18719#issuecomment-554751397

MBroertjes commented 4 years ago

Proposing punt...

This was punted for 3.0 but didn't make it? What's the new ETA for this feature? It would be of great benifit for the corporation I'm working for.

ajcvickers commented 4 years ago

@MBroertjes We're still working on planning, but it's looking like this will be in 5.0, hence the milestone currently assigned.

stantoxt commented 4 years ago

I hope this feature can be moved up, this is a really wanted feature.

AndriySvyryd commented 4 years ago

Related to https://github.com/dotnet/efcore/issues/15671

webwarrior06 commented 4 years ago

I solved it checking from where the entity builder is called, (from "add-migration Xyz" command or the normal dbContext operations) If a migration operation calls the builder, I ignore the entity that I want to ignore just for migration purposes. Here is my workaround; https://stackoverflow.com/a/62281191/1928672

aloksharma1 commented 2 years ago

did this ever got added in new versions, +1000000 btw :)

AndriySvyryd commented 2 years ago

@aloksharma1 Yes, it's in 5.0.0

VeMike commented 1 year ago

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 commented 1 year ago

@VeMike Moved here: https://github.com/dotnet/efcore/issues/30079