Code First: Database Initialization

Description Article
Table of Contents
Summary

Database initialization is the process of create the Entity Data Model (EDM) in memory using the Code First conventions and next create the database that will be used to store the data according the option configured.

Description

How It works

Initialization occurs one time per application instance (i.e. AppDomain) and once per context.

The process is triggered automatically the first time a context is used and occurs in a lazily way: It is only initiated when the context is used, an not when instantiated.

Although its triggered automatically, this process can be triggered programatically by the developer.

The database initialization process can also be disabled. This would be the correct action to due in a prodution environment.

Entity Framework package includes three implementations of the interface IDatabaseInitializer. These implementations can be derived in order to customize behavior.

Initializer Component Description Comments
CreateDatabaseIfNotExists This initializer will create the database if none exists as per the configuration. However, if the model (entity classes) changes an exception will be thrown This is the default initializer for all contexts
DropCreateDatabaseIfModelChanges This initializer drops an existing database and creates a new database, if the model (entity classes) have been changed Only usefull during development
DropCreateDatabaseAlways This initializer drops an existing database every time the application runs, regardless of whether the model (entity classes) have changed or not Usefull during integration tests in order to reset the database to a well-known state before running a test

A custom initializer can be derived of an existing one, in order to guarantee that data is inserted in the created tables in order to provide test data for unit or integration tests. If this is the case the Seed method must be overrided.

 How To Use It

The use of a particular database initializer can be done programatically using the Database.SetInitializer() method or via “app.config” or “web.config” configuration file.

Operations
How to configure a initializer option
How to do it

Configuring programatically an Entity Framework initializer:

static void Main(string[] args)
{
    Database.SetInitializer(new DropCreateDatabaseAlways<BreakWayContext>());

    using (var ctx = new BreakWayContext())
    {
        ...
	// Initializer will be called here:
        ctx.Destination.Add(destination);
        ...
    }

}

Alternative way:

public class BreakAwayContext: DbContext
{
  public BreakAwayContext() : base("BreakAwayDatabase")
  {
     Database.SetInitializer<BreakAwayContext>(new DropCreateDatabaseAlways<BreakAwayContext>());
  }

  public DbSet<Destination> Destinations { get; set; }
  //...
}

Configuring an Entity Framework initializer in the application configuration file:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="DatabaseInitializerForType EF.Demo.BreakAwayContext, EF.Demo"
            value="System.Data.Entity.DropCreateDatabaseAlways, EntityFramework" />
  </appSettings>
</configuration>

Configuring an Entity Framework initializer in the application configuration file (EF4.3 and onwards):

<configuration>
  <configSections>
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  </configSections>
  <entityFramework>
    <contexts>
      <context type="EF.Demo.BreakAwayContext, EF.Demo">
        <databaseInitializer type="System.Data.Entity.DropCreateDatabaseAlways, EntityFramework" />
    </contexts>
  </entityFramework>
</configuration>
How to disable database initialization
How to do it

Switching off programatically the database initilization process:

public class BreakAwayContext: DbContext
{
  public BreakAwayContext() : base("BreakAwayDBConnectionString")
  {
    Database.SetInitializer<BreakAwayContext>(null);
  }

  public DbSet<Destination> Destinations { get; set; }
  //...

}

Switching off the database initilization process in the application configuration file:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="DatabaseInitializerForType EF.Demo.BreakAwayContext, EF.Demo" value="Disabled" />
   </appSettings>
</configuration>

Switching off the database initilization process in the application configuration file (EF4.3 and onwards):

<configuration>
  <configSections>
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  </configSections>
  <entityFramework>
    <contexts>
      <context type="EF.Demo.BreakAwayContext, EF.Demo" disableDatabaseInitialization="true" />
    </contexts>
  </entityFramework>
</configuration>
Create custom database initializer (validate database and model compatibility)

Model compatibility currently uses the following rules:

i) If the context was created using either the Model First or Database First approach then the model is assumed to be compatible with the database and this method returns true.

ii) For Code First the model is considered compatible if the model is stored in the database in the Migrations history table and that model has no differences from the current model as determined by Migrations model differ.

If the model is not stored in the database but an EF 4.1/4.2 model hash is found instead, then this is used to check for compatibility.

How to do it

Configuring programatically a custom initializer:

public class ValidateDatabaseOnly<TContext> : IDatabaseInitializer<TContext> where TContext : DbContext
{
  public void InitializeDatabase(TContext context)
  {
    if (!context.Database.Exists())
    {
      throw new ConfigurationException(
        "Database does not exist");
    }
    else
    {
      if (!context.Database.CompatibleWithModel(true))
      {
        throw new InvalidOperationException(
          "The database is not compatible with the entity model.");
      }
    }
  }
}

Configuring a custom initializer in the application configuration file:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="DatabaseInitializerForType EF.Demo.BreakAWayContext, EF.Demo"
            value="EF.Demo.ValidateDatabaseOnly, EF.Demo" />
  </appSettings>
</configuration>
Create custom database initializer: Provide data for unit and integration tests
How to do it
public class BreakAwayDBInitializer : DropCreateDatabaseAlways<BreakAwayContext>
{
        protected override void Seed(BreakAwayContext context)
        {
            IList<Standard> defaultStandards = new List<Standard>();

            defaultStandards.Add(new Standard() { StandardName = "Standard 1", Description = "First Standard" });
            defaultStandards.Add(new Standard() { StandardName = "Standard 2", Description = "Second Standard" });
            defaultStandards.Add(new Standard() { StandardName = "Standard 3", Description = "Third Standard" });

            foreach (Standard std in defaultStandards)
                context.Standards.Add(std);

            base.Seed(context);
        }
    }
How to disable database intialization on context classes derived on a generic base class
How to do it
/Fetch all the DbContexts types in the assembly
var allDbContextsTypes = Assembly.GetExecutingAssembly().GetTypes().Where(t => t.BaseType == (typeof(BASEDBCONTEXTTYPE))).ToList();

foreach (Type dbContextType in allDbContextsTypes)
{
    //Get the SetInitializerMethod
    MethodInfo initializerMethod = typeof(Database).GetMethod("SetInitializer");

    //Make it generic! (Oh yeah)
    MethodInfo dbContextInitializerMethod = initializerMethod.MakeGenericMethod(dbContextType);

    //Invoke the method with null initializer
    dbContextInitializerMethod.Invoke(null, new object[]{null});
}