First EF code: inherited dbcontext creates two databases

I am trying to create a basic dbcontext that contains all the shared objects that will always be reused in several projects, such as pages, users, roles, navigation, etc.

In doing so, I have a ContextBase class that inherits DbContext and defines all the necessary DbSets. Then I have a Context class that inherits ContextBase, where I define project-specific DbSets. Classes are defined as follows:

public class ContextBase : DbContext { public virtual DbSet<User> Users { get; set; } //more sets protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Configurations.Add(new UsersConfiguration()); //add more configurations } } public class Context : ContextBase { public DbSet<Building> Buildings { get; set; } //some more project specific sets protected override void OnModelCreating(DbModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.Configurations.Add(new BuildingsConfiguration()); //add more project specific configs } } 

In my global.asax:

 Database.SetInitializer(new MigrateDatabaseToLatestVersion<Context, Configuration>()); 

where Configuration refers to a class that inherits from DbMigrationsConfiguration and overrides the Seed method.

Two context classes are defined in the same namespace, but intersect (so that I can update the base project in several existing projects without touching the project code) - I'm not sure if this is relevant.

MY PROBLEM: When running this code, it works fine, but when searching the database, it actually creates two different databases! One containing all the base entities, and one containing the base and user BOTH tables. CRUD operations are only performed in the user version (which is obviously what I want), but why does it also create another one?

Any help is appreciated, thanks!

UPDATE:

The following code is what I came across. It is not perfect, but it works. I would still like to receive feedback on how to improve this, but nonetheless, I hope this helps the further process. I REALLY DO NOT RECOMMEND THIS! This is very error prone and very unpleasant to debug. I just post this to find out if there are any better ideas or implementations to achieve this.

One (but not the only) problem that still exists is that MVC views must be manually added to projects. I added it to the Nuget package, but it takes 2 to 3 hours to apply the nuget package with so many files when VS is connected to TFS. With some additional work and a custom view engine, views can be precompiled ( http://blog.davidebbo.com/2011/06/precompile-your-mvc-views-using.html ).

The solution is divided into projects of the basic structure and user projects (each category includes its own models and repository template). Framework projects are packaged in the Nuget package, and then installed in any custom projects, making it easy to add the general functions of any project, such as user management, role and permissions, content management, etc. (Often called a boiler room) any new projects. This allows you to transfer any improvements to the template in any existing user projects.

Custom database initializer:

 public class MyMigrateDatabaseToLatestVersion : IDatabaseInitializer<Context> { public void InitializeDatabase(Context context) { //create the base migrator var baseConfig = new FrameworkConfiguration(); var migratorBase = new DbMigrator(baseConfig); //create the custom migrator var customConfig = new Configuration(); var migratorCustom = new DbMigrator(customConfig); //now I need to check what migrations have not yet been applied //and then run them in the correct order if (migratorBase.GetPendingMigrations().Count() > 0) { try { migratorBase.Update(); } catch (System.Data.Entity.Migrations.Infrastructure.AutomaticMigrationsDisabledException) { //if an error occured, the seed would not have run, so we run it again. baseConfig.RunSeed(context); } } if (migratorCustom.GetPendingMigrations().Count() > 0) { try { migratorCustom.Update(); } catch (System.Data.Entity.Migrations.Infrastructure.AutomaticMigrationsDisabledException) { //if an error occured, the seed would not have run, so we run it again. customConfig.RunSeed(context); } } } } 

DB Database Migration Configuration:

 public class FrameworkConfiguration: DbMigrationsConfiguration<Repository.ContextBase> { public Configuration() { AutomaticMigrationsEnabled = false; } public void RunSeed(Repository.ContextBase context) { Seed(context); } protected override void Seed(Repository.ContextBase context) { // This method will be called at every app start so it should use the AddOrUpdate method rather than just Add. FrameworkDatabaseSeed.Seed(context); } } 

Configuration of custom DB projects:

 public class Configuration : DbMigrationsConfiguration<Repository.Context> { public Configuration() { AutomaticMigrationsEnabled = false; } public void RunSeed(Repository.Context context) { Seed(context); } protected override void Seed(Repository.Context context) { // This method will be called at every app start so it should use the AddOrUpdate method rather than just Add. CustomDatabaseSeed.Seed(context); } } 

Custom dbcontext

 //nothing special here, simply inherit ContextBase, IContext interface is purely for DI public class Context : ContextBase, IContext { //Add the custom DBsets, ie public DbSet<Chart> Charts { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); //Assign the model configs, ie modelBuilder.Configurations.Add(new ChartConfiguration()); } } 

DbContext Frame:

 //again nothing special public class ContextBase: DbContext { //example DbSet's public virtual DbSet<Models.User> Users { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder); } 

In global.asax AppStart:

  //first remove the base context initialiser Database.SetInitializer<ContextBase>(null); //set the inherited context initializer Database.SetInitializer(new MyMigrateDatabaseToLatestVersion()); 

In the web.config file:

 <connectionStrings> <!--put the exact same connection string twice here and name it the same as the base and overridden context. That way they point to the same database. --> <add name="Context" connectionString="Data Source=.\SQLEXPRESS; Initial Catalog=CMS2013; Integrated Security=SSPI;MultipleActiveResultSets=true;" providerName="System.Data.SqlClient"/> <add name="ContextBase" connectionString="Data Source=.\SQLEXPRESS; Initial Catalog=CMS2013; Integrated Security=SSPI;MultipleActiveResultSets=true;" providerName="System.Data.SqlClient"/> </connectionStrings> 
+7
source share
2 answers

(from comments)

You create ContextBase objects directly, apparently like new T() in a generic method with ContextBase as an argument of a generic type, so any initializers for ContextBase also run. To prevent the creation of ContextBase objects (if it should never be created directly, if a derived context should always be used), you can mark it as abstract .

+5
source

Your ContextBase also has an initializer .. You can remove this with

 Database.SetInitializer<ContextBase>(null); 
+3
source

All Articles