Monthly Archives: January 2019

Multiple EntityFramework contexts with code-first migrations

I’ve encountered an issue with code-first migrations in a brown field project which uses Oracle DBMS for data persistence. First to describe my goal in short:

  • Store all application data in single database
  • Application may have multiple data contexts
  • Old parts of database will not have any migrations, as they are created and updated externally
  • Application will have modules which don’t have tight dependency to some central data layer
  • Each module may have it’s own EF DB context. And each module may perform code-first migrations independently of other modules

Sounds quite straight forward, and it is, until we’ve hit a bug in EF. So, we created additional DbContexts, with their own migrations. Upon running the migration, what we’ve encountered is error back from Oracle.

ORA-00955: name is already used by an existing object

What has happened is that EF is attempting to create __MigrationHistory table which already exists. So, although there was another context which created the MigrationHistory table, next context attempts to create it again. We’ve found this bug reported in EF GitHub repo, all the way back in 2016. Workaround that bug author has used is to have separate __MigrationHistory table per context, which I did not like for a couple of reasons.

  • I may have many (more than 5) contexts, and I don’t want variants of __MigrationHistory table to clutter the databases
  • Configuration which allows this change is AppDomain wide, so we would have to either have separate apps to do migrations, or do juggling of AppDomains per DB context

Over investigation of the problem, what we’ve found is that it happens only if user does not use SQL Server dbo schema. Since we use Oracle, this was clearly the case. So we found two potential workarounds. One is clearly, create dbo user and __MigrationHistory table inside it. A cleaner one is to set default schema for HistoryContext of EF. This is EF internal context which is used to read migrations history. So, what you need to do is:Annotate DbContext with your own configuration (MyConfiguration)

1. Annotate DbContext with your own configuration (MyConfiguration)

    [DbConfigurationType(typeof(MyConfiguration))]
    public class MyDbContext : DbContext

2. Implement the configuration. It’s purpose is to return subclasses history context. In this case MyHistoryContext

    public class MyConfiguration : DbConfiguration
    {
        public MyConfiguration ()
        {
            SetProviderServices("Oracle.DataAccess.Client", EFOracleProviderServices.Instance);
            SetHistoryContext("Oracle.DataAccess.Client", (connection, defaultSchema) => new MyHistoryContext(connection, defaultSchema));
        }
    }

3. Implement the subclasses context to use your desired schema

    public class MyHistoryContext : HistoryContext
    {
        public MyHistoryContext(DbConnection dbConnection, string defaultSchema)
            : base(dbConnection, defaultSchema)
        {
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.HasDefaultSchema("CONTEXT_NAME");
        }
    }