Place to put Database.SetInitializer

43,557

Solution 1

You would need a mechanism to call the Database.SetInitializer method before the very first usage of the DbContext. That is why its usually called in the Global.asax file.

You can create a class with an initialization method in your tm.Service project and call it in the Application_Start method and put the Database.SetInitializer in that initialization method.

Its OK to supply the connection string from a setting file.

Solution 2

To avoid the coupling, I would prefer not to set the initializer outside the Assembly that contains the DataContext. So, I added a static constructor for the DataContext. This way every project referencing this Assembly will enjoy the initializer without explicitly setting it, and the initializer is set only once per process.

static MyDataContext()
{
   Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyDataContext, Configuration>());
}

The connection string will of course be taken from the application configuration file.

Solution 3

I put it on the DbContext constructor and works for me.

public myDbContext() : base(connectionToDatabase) {
        Database.SetInitializer<myDbContext>(null);
    }

The solution above will work, but it is not as efficient as the following code:

  protected void Application_Start()
    {
        Database.SetInitializer<myDbContext>(null);
    }

In my case I don't have a reference of my DAL on the UI and for that reason what I did is, I create a EntityFramework config and register my setting using using reflection.

 protected void Application_Start()
    {           
        EntityFrameworkConfig.RegisterSettings();
    }


 public static class EntityFrameworkConfig
{
    public static void RegisterSettings()
    {
        // Use the file name to load the assembly into the current
        // application domain.
        Assembly a = Assembly.Load("MyAssembly");
        // Get the type to use.
        Type myType = a.GetType("MyType");
        // Get the method to call.
        MethodInfo myMethod = myType.GetMethod("MySettingsMethod");
        // Create an instance.
        object obj = Activator.CreateInstance(MyType);
        // Execute the method.
        myMethod.Invoke(obj, null);
    }
}

  public void Configurations()
    {
      //Other settings
        Database.SetInitializer<myDbContext>(null);
    }

Updated

With Entity Framework 6, now you can use the NullDatabaseInitializer

Database.SetInitializer(new NullDatabaseInitializer<MyDbContext>());

Solution 4

Microsoft made it possible, for EF6 onwards, to configure one initializer per database context in the config file of the application. See the last section on this Microsoft page: https://msdn.microsoft.com/en-us/data/jj556606.aspx

This, like the "Global.asax" approach, has the advantage that e.g. unit test projects can use a different initializer for the same database context.

Share:
43,557
Paweł Staniec
Author by

Paweł Staniec

Updated on March 25, 2020

Comments

  • Paweł Staniec
    Paweł Staniec about 4 years

    I'm working on a project that at can end up with multiple UI versions / variants, but so far I've got two subprojects in my solution Web - containing Web interface with ASP.NET MVC. Service project is place where I have my database context and models defined.

    My Goal is to have minimum or possibly no references to EF specific code in my Web project. I want it to be independent so when I switch the dlls with service backend ( from let say SQL to XML or MySQL ) I shouldn't make multiple modifications in my MVC project.

    This is how it looks :

    Project layout

    My Questions are: - so far I've found no example of using Database.SetInitializer in other place than Global.asax. I'd like to put database re-creation if model changed in my factory-like DatabaseContextProvider class or in service class that pulls out data from context and provides it to the UI with DTOs. Are there any cons of that location ? - I would like to have the context's connectionString to be configurable with Properties/Settings.settings file - is that reasonable ?

  • Holf
    Holf over 10 years
    A potential issue with doing this is it could get called every time the myDbContext class is constructed, which could very well be each time you use the database. I would imagine this is a reasonably expensive operation and you don't want this to happen. Using Global.asax Application_Start or a Static Constructor in the DataContext class guarantees that the code is only called once, when the application is started.
  • Ricardo Huertas
    Ricardo Huertas over 10 years
    I agree with Holf, the code should be on the application_start
  • Pragmateek
    Pragmateek almost 10 years
    Not sure this is a good idea because you then have a tight coupling between the DbContext and the initializer. The initialization policy depends on the context, e.g. for tests you would use a DropCreateDatabaseAlways and for production a CreateDatabaseIfNotExists...
  • Daniel Mackay
    Daniel Mackay over 7 years
    I believe it is one initializer per context, not per database. Multiple contexts can operate on the same DB.
  • Carsten Führmann
    Carsten Führmann over 7 years
    @DanielMackay But I did write "database context"'! Did you perchance overlook the word "context" because of the line wrap directly after the word "database"?
  • SpoiledTechie.com
    SpoiledTechie.com about 7 years
    they don't recommend the config, rather they say you can do that, as well as do it in the code. To them, you now can do it either way.
  • Carsten Führmann
    Carsten Führmann about 7 years
    @SpoiledTechie.com Thanks, I fixed my answer accordingly.
  • binki
    binki almost 6 years
    @Pragmateek For tests, you can always for the static initializer of the type to run and then call Database.SetInitializer() directly. For many people using migrations, the set of migrations that should be used by external consumers will already be closely tied to the model itself so the static initializer is probably a good place to specify a default initailizer that would make sense for most normal (e.g., non-test/dev) consumers.