3

I am setting up an automated integration test environment for a large, existing Entity Framework 6 project that uses a MySQL database.

My goal is to create a fresh, empty database schema directly from the current DbContext model for each test run. I want to completely ignore the project's existing migration history, as running dozens of migrations is slow and unnecessary for these tests.

It seems like this should be straightforward, but the default EF6 behaviors always try to use the migration history.

What I've tried that doesn't work

The most intuitive approaches fail. For example, if I just create a context and call Create():

using (var context = new MyDbContext(testConnectionString)) { // This fails because EF detects a Migrations/Configuration.cs and // tries to use the migration history, which I want to avoid. context.Database.Create(); } 

Using the standard CreateDatabaseIfNotExists<T> initializer has the same problem; it seems to be aware of the migration configuration and doesn't just build from the model.

What currently works (but feels overly complex)

I've managed to get it working with a custom IDatabaseInitializer. This approach feels very heavy-handed, and I'm wondering if there's a simpler way.

My working solution has three parts:

1. A custom IDatabaseInitializer

This initializer drops all existing tables and then generates and executes a DDL script from the current model.

public class TestDatabaseInitializer : IDatabaseInitializer<MyDbContext> { public void InitializeDatabase(MyDbContext context) { // Connection must be a MySqlConnection var connection = (MySql.Data.MySqlClient.MySqlConnection)context.Database.Connection; // 1. Drop all existing tables to ensure a clean slate var tableNames = context.Database.SqlQuery<string>("...query to get all table names...").ToList(); if (tableNames.Any()) { var dropScriptText = "...script to drop all tables..."; new MySql.Data.MySqlClient.MySqlScript(connection, dropScriptText).Execute(); } // 2. Generate a DDL script from the current model var dbCreationScript = ((IObjectContextAdapter)context).ObjectContext.CreateDatabaseScript(); // (Note: I also have to patch this script with Regex for a separate bug, but that's not relevant to this question) // 3. Execute the DDL script var createScript = new MySql.Data.MySqlClient.MySqlScript(connection, dbCreationScript); createScript.Execute(); } } 

2. A dedicated TestDbContext

To keep my production MyDbContext clean, I created a derived context for testing that sets the custom initializer.

public class TestDbContext : MyDbContext { public TestDbContext(string connectionString) : base(connectionString) { Database.SetInitializer(new TestDatabaseInitializer()); } } 

3. The test method

The test method instantiates the TestDbContext and forces the initialization.

[Test] public void CanCreateDatabaseFromModel() { var testConnectionString = "server=localhost;...etc"; using (var context = new TestDbContext(testConnectionString)) { // This triggers the custom initializer context.Database.Initialize(force: true); // Assert that tables were created... Assert.IsTrue(context.Database.Exists()); } } 

My question

While my custom IDatabaseInitializer works, it feels like I'm rebuilding a feature that should already exist. I had to manually write logic to drop all tables and then use the MySqlScript class to execute a generated script.

Is there a more direct or "blessed" way in Entity Framework 6 to tell a DbContext instance "Ignore all migration history and just create a database schema based on your current in-memory model configuration"?

I'm looking for something as simple as a hypothetical context.Database.CreateFromModel(force: true) that doesn't get entangled with the migrations pipeline.

3
  • EF has nothing to do with "duplicating" a "physical" database; and the back end (MySql) is totally unaware of EF. You use the existing DDL (or "generate" it from the "production" database) to create a new database with a new (test) name. Then point the DbContext to it. Commented Sep 24 at 16:12
  • Thank you, that's a great point for schema-first testing; however, we're using a code-first approach, so we generate the schema directly from the model at runtime to guarantee the tests always run against the latest entity definitions and avoid the risk of a stale DDL script. Commented Sep 25 at 7:48
  • According to the documentation, I think you should use context.Database.EnsureCreated() as you can read here - learn.microsoft.com/en-us/dotnet/api/…. This method ignores Migrations as you request Commented Sep 30 at 2:27

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.