Question

We have an MVC 5 project that contains several Areas. The 'main' application has a model called Person. Each Area has a class derived from Person.

Each Area also has its own DbContext, derived from the DbContext from the 'main' application.

The project is set up to make use of Code First Automatic Migrations in EF6. The project is also configured so that specific Areas are 'switched on/off' before Automatic Migrations take place.

The idea here is that when the application is deployed, Automatic Migrations create a database schema based on the Area that has been 'activated' if any. In other words, on 'first run' if Area A has been activated, Automattic Migrations should create a database containing 2 Tables, Person and AreaAPerson. If no Area has been activated then only the table for Person must be created. Only one Area will ever be 'active' at a time. So if no Area is activated, the migration should ignore the models under the Areas, this is the result we are looking for.

What is happening is that ALL Models from ALL Areas are being created in the DB. But how can this be? We are specifying the Migration Configuration to be used?

I believe this has to do with the 1-1 Relationship between Person and its children, and how EF6 finds 'related' Entities (maybe I am wrong) but this was determined by commenting out parts of the code one-by-one in the class structure until the only possible thing left to remove was the AreaPerson class, after which it is obviously not migrated up.

    namespace MyProject
{
    public class ApplicationDbContext : IdentityDbContext
    {
        public ApplicationDbContext() : base("ApplicationDbContext")
        {
        }

        public virtual DbSet<Person> People { get; set; }
    }

    public class Person
    {
        public string Age { get; set; }
        public int Id { get; set; }
        public string Name { get; set; }
        public string SomePropertyA { get; set; }
        public string Surname { get; set; }
    }

//Global.asax.cs
    public class MvcApplication : HttpApplication
    {
        protected void Application_Start()
        {
            Database.SetInitializer(new CreateDatabaseIfNotExists<ApplicationDbContext>());

            DbMigrator dbMigrator;

            //NOTE: not the actual code, but this is what is comes down to
            if (AreaA.IsActive)
                dbMigrator = new DbMigrator(new Area_A_Configuration());
            else if(AreaB.IsActive)
                dbMigrator = new DbMigrator(new Area_B_Configuration());
            else
                dbMigrator = new DbMigrator(new Configuration());

            dbMigrator.Update();
        }
    }
}

namespace MyProject.Areas.Area_A
{
    public class Area_A_DbContext : ApplicationDbContext
    {
        public virtual DbSet<Area_A_Person> A_People { get; set; }
    }

    public class Area_A_Person : Person
    {
        public string SomeProperty_A { get; set; }
    }

    internal sealed class Area_A_Configuration : DbMigrationsConfiguration<Area_A_DbContext>
    {
        public Configuration() : base()
        {
            AutomaticMigrationsEnabled = true;
            AutomaticMigrationDataLossAllowed = true;
        }
    }
}

namespace MyProject.Areas.Area_B
{
    public class Area_B_DbContext : ApplicationDbContext
    {
        public virtual DbSet<Area_B_Person> B_People { get; set; }
    }

    public class Area_B_Person : Person
    {
        public string SomeProperty_B { get; set; }
    }

    internal sealed class Area_B_Configuration : DbMigrationsConfiguration<Area_B_DbContext>
    {
        public Configuration() : base()
        {
            AutomaticMigrationsEnabled = true;
            AutomaticMigrationDataLossAllowed = true;
        }
    }
}
1
1
8/16/2018 10:40:31 AM

Popular Answer

Turns out the solution was quite simple: EF6 'explores' the models and automatically adds related models to the db context (although we are still looking for a way to restrict this to only entities defined as a DbSet<> in the DbContext)

Thanks to this question we only have to add modelBuilder.Ignore<Area_B_Person>(); to ApplicationDbContext.onModelCreating() and Models from Area_B will not be included in the migration. Similarly for any Model in any Area.

Hope this helps someone else in the future.

1
8/17/2018 6:44:36 AM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow