We run migrations from within our application to create databases on the fly. We also use migrations in our unit/integration tests to create databases for the tests to use. A few months ago we noticed the run-time of our tests substantially increased and we've been able to narrow it down to the instantiation of the DbMigrator class. Even with a very simple Configuration class it still takes ~10 seconds to create the DbMigrator.
For example, here's the Configuration class taken from the "Elastic DB Tools - Entity Framework" sample application.
internal sealed class Configuration : DbMigrationsConfiguration<ElasticScaleContext<int>>
{
public Configuration()
{
this.AutomaticMigrationsEnabled = false;
this.ContextKey = "CodeFirstNewDatabaseSample.BloggingContext";
}
}
Here is the code used to create and run the migrations.
var configurator = new Configuration();
configurator.TargetDatabase = new DbConnectionInfo(connStrBldr.ConnectionString, "System.Data.SqlClient");
var migrator = new DbMigrator(configurator);
migrator.Update();
And here's the trace information from VS2015.
Time to instantiate Configuration
Time to set the TargetDatabase property
Time to instantiate DbMigrator
We're using Entity Framework 6.1.3. Has anyone else experienced this?
Related
I'm working on a .NET 4.5.2 project that creates an In-Memory db from an .mdf file every time we run the Integration tests.
The db works fairly well most of the time, but sometimes, when we make changes on the schema of a table, or add/delete a table altogether, we get problems like the following:
Message:
OneTimeSetUp: System.Data.SqlClient.SqlException : There is already an object named 'SomeTable' in the database
We have narrowed it down to the fact that EF migrations get all messed up when we want to update the test db schema after a merge (known issue). It seems like adding an empty migration everytime we have one of these issues fixes the problem, however, that workaround it's very tacky.
My question is: Is there a way to prevent this kind of issues? Maybe a cleaner workaround?
For some extra content, I'll describe how we're doing things (maybe we're messing up somehow):
We have a Db.mdf file that gets loaded by a LocalDbHelper before running any test:
With this code:
public static void PrepareEmptyDb()
{
var migrationConfiguration = new Configuration()
{
AutomaticMigrationsEnabled = true,
AutomaticMigrationDataLossAllowed = true
};
var migrator = new DbMigrator(migrationConfiguration);
migrator.Update();
}
This code is meant to be run in a OneTimeSetup at the IntegrationTestBase class.
And this is the code in the Configuration class (this is at our code first Persistance project, where all migrations reside):
internal sealed class Configuration : DbMigrationsConfiguration<Context.DbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
protected override void Seed(Context.DbContext context)
{
context.Settings.AddOrUpdate(
p => p.Name,
new Setting { Name = SettingNames.RoundingDirection, Value = "Up" },
new Setting { Name = SettingNames.RoundingValue, Value = "10" },
new Setting { Name = SettingNames.RateCacheLifetimeMinutes, Value = "30" });
}
}
Any help would be greatly appreciated, since this issue has really been annoying us for a while now.
EDIT: I've found this link that seem to suggest that, for older versions of .NET, this workaround was the recommended fix suggested by Microsoft themselves, but if anyone has a better way to fix it (or to automatize it) it would be greatly appreciated.
Adding an empty migration seems to be the only way to fix this. No workarounds or fixes other than upgrading to Core, sadly.
In certain test environments, I have configured my application to create a new instance of it's database using Entity Framework migrations when the database does not already exist.
I am also using Hangfire, and have configured it use SQL Server in my OWIN startup class. At present I am instantiating a new instance of my DbContext to force database creation prior to configuring Hangfire to use the database:
public class Startup
{
public void Configuration(IAppBuilder app)
{
using (var dbContext = new MyDbContext())
{
// Force database creation before configuring Hangfire to use it.
}
GlobalConfiguration.Configuration.UseSqlServerStorage("myConnection");
// ...
}
}
This feels a bit hacky. What is the recommended way to ensure Entity Framework has created the database before it is used outside of the DbContext?
Turns out that the snippet in the question isn't necessarily enough by itself (depending upon platform and other EF configuration settings), so we actually make it explicit in the code now (as per Diana's comment), which also makes it feel less hacky:
// Trigger database creation before Hangfire tries to use it.
var initializer = new MigrateDatabaseToLatestVersion<MyDbContext, MyConfiguration>(true);
Database.SetInitializer(initializer);
var connectionString = this.Configuration.GetConnectionString("MyConnectionString");
using (var dbContext = new MyDbContext(connectionString))
{
dbContext.Database.Initialize(false);
}
I would like to be able to unit test using my code first/migrations entity framework project.
My current method does the following:
Create the DataContext
Creates the repository
Creares unit of working using DataContext
Creates my service layer
After step 1. I would like to be able say to entity framework, using my migrations/migrations folder recreate the database every time it runs.
I current send in my Datacontext a custom string which represents what connection string to use, my code looks like:
[TestCase]
public void TestMethod1()
{
var systemContextTest = new SystemContext("SystemContextTest");
IRepository<PublicQueries> repos = new Repository<PublicQueries>(systemContextTest);
var uow = new UnitOfWork(systemContextTest);
var service = new PublicQueryService(repos);
service.Find(0);
}
I just want to be able to create the database, using migrations everytime this test is ran!
Thanks
-UPDATE-
I have tried:
Database.SetInitializer<YourContext>(new MigrateDatabaseToLatestVersion<YourContext, YourMigrationConfiguration>());
But this results in
System.Data.Entity.Core.EntityCommandExecutionException : An error occurred while executing the command definition. See the inner exception for details.
----> System.Data.SqlClient.SqlException : Invalid object name
Which means its still not creating it.
I just want to using my migration files/code first migrations to create a new fresh database.
-- UPDATE 2 --
When adding Database.SetInitializer(new DropCreateDatabaseAlways<SystemContext>());
I get the following error:
System.InvalidOperationException : The DropCreateDatabaseAlways initializer did not drop or create the database backing context 'SystemContext' because Migrations are enabled for the context. Use Migrations to manage the database for this context, for example by running the 'Update-Database' command from the Package Manager Console.
My SystemContext Constructor i am using for testing looks like:
public SystemContext(string connectionstringname) :
base(connectionstringname)
{
Database.SetInitializer<SystemContext>(null);
Configuration.ProxyCreationEnabled = false;
}
Updatad answer:
Implement a custom database initializer
private DbMigrationsConfiguration configuration;
public void InitializeDatabase(C context) {
context.Database.Delete();
context.Database.Create();
var migrator = new DbMigrator(configuration);
migrator.Update();
}
and put this line at the beginning of the test method.
Database.SetInitializer(new MyCustomInitializer<SystemContext>());
We are intensively used Entity Framework 4.3 with a code first .NET 4.0 based project within several sites, everything works smooth, fast and bugless, but to enable the last speed improvements made by the Entity Framework team we are now planning an upgrade to EF6 and .NET 4.5
After amending a couple of using clauses (due to the namespaces changes in the latest releases) everything seems to working properly if starting with an empty db, but trying to open an existing customer database will get an exception as soon as the Context() construction happens, apparently something is wrong with the code based migration.
My code based migration configuration is the following:
internal sealed class Configuration : DbMigrationsConfiguration<Context>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
AutomaticMigrationDataLossAllowed = true;
}
}
With this application initialiser (program.cs)
Database.SetInitializer(new MigrateDatabaseToLatestVersion<Context, Configuration>());
Database.DefaultConnectionFactory = new UniversalDbConnection();
Having UniversalDbConnection declared as
class UniversalDbConnection : IDbConnectionFactory
{
public DbConnection CreateConnection(string givenString)
{
switch (Preferences.DatabaseVendor)
{
case ConnectionPreset.PostgreSQL:
return new PgSqlConnection(Preferences.ConnectionString);
default:
SqlConnectionFactory factory = new SqlConnectionFactory(Preferences.ConnectionString);
return factory.CreateConnection(Preferences.ConnectionString);
}
}
}
Unfortunately an exception claiming:
The object 'FK_StockTests_FormulaSteps_Step_Id' is dependent on column 'Step_Id'.
ALTER TABLE DROP COLUMN Step_Id failed because one or more objects access this column arises
In our production environment, we have an automated deploy script that takes down our site, runs migrations, and then brings it back online. We'd like to avoid taking the site down by just switching to the new code when there aren't any migrations that need to be run.
Does entity framework have a command like "Update-Database" that would allow us to check if there are migrations to run?
The DbMigrator class has the GetPendingMigrations method which sounds like the exact one you look for. It should be something like
YourMigrationsConfiguration cfg = new YourMigrationsConfiguration();
cfg.TargetDatabase =
new DbConnectionInfo(
theConnectionString,
"provider" );
DbMigrator dbMigrator = new DbMigrator( cfg );
if ( dbMigrator.GetPendingMigrations().Any() )
{
// there are pending migrations
// do whatever you want, for example
dbMigrator.Update();
}
I use DbContext.Database.CompatibleWithModel() with EF 6.1.3