We've run into some weird behaviour from Entity Framework 6 when applying our code-first migrations. The problem only seems to happen in our production environment of course. We run an ASP.NET website and have a separate application just to apply database changes such as dropping, seeding and applying migrations.
What happens is that before applying our code-first migrations EF seems to be trying to migrate the __MigrationHistory table by applying running the following snippet:
CREATE TABLE [dbo].[__MigrationHistory2] (
[MigrationId] [nvarchar](150) NOT NULL,
[ContextKey] [nvarchar](300) NOT NULL,
[Model] [varbinary](max) NOT NULL,
[ProductVersion] [nvarchar](32) NOT NULL,
CONSTRAINT [PK_dbo.__MigrationHistory2] PRIMARY KEY ([MigrationId], [ContextKey])
)
INSERT INTO [dbo].[__MigrationHistory2]
SELECT LEFT([MigrationId], 150), 'SOP.DataAccess.Migrations.Configuration', [Model], LEFT([ProductVersion], 32) FROM [dbo].[__MigrationHistory]
DROP TABLE [dbo].[__MigrationHistory]
EXECUTE sp_rename @objname = N'dbo.__MigrationHistory2', @newname = N'__MigrationHistory', @objtype = N'OBJECT'
As far as I understand this should only happen when upgrading from EF5 to EF6. However, we've only ever used EF6, so this behaviour seems very strange.
The real problem comes as this "migration" seems to happen continually. On the first production release where we had this happen all turned out fine, but on later releases running the above snippet makes EF fail with the exception:
There is already an object named 'PK_dbo.__MigrationHistory2' in the database.
Could not create constraint or index. See previous errors.
This makes sense as the code-snippet doesn't seem to rename the PK contraint/index, so repeated attempts at running it will fail.
Even weirder is that multiple attempts at applying out migrations on one of our releases in the end seemed cause EF to not apply this migration to __MigrationHistory and instead just applied our migrations and everything was fine after that... until our next release deployment.
Has anyone out there got a clue why this is happening and how to fix it/prevent it from happening again?
Update: some extra details
The application we deploy migrations with runs the following code, which I consider the essential part related to the problem:
// This configuration extends DbMigrationsConfiguration<MyDbContext>, with the following props:
// AutomaticMigrationsEnabled = false;
// AutomaticMigrationDataLossAllowed = true;
var configuration = new DataAccess.Migrations.Configuration();
var migrator = new DbMigrator(configuration);
var migrations = migrator.GetPendingMigrations().ToList();
if (!context.Database.CompatibleWithModel(false) || migrations.Any())
{
Console.WriteLine("Database not compatible with model.");
if (migrations.Any())
{
Console.WriteLine("There are pending migrations.");
var scriptor = new MigratorScriptingDecorator(migrator);
foreach (var migration in migrations)
{
var script = scriptor.ScriptUpdate(null, migration);
if (!string.IsNullOrEmpty(script))
{
Console.WriteLine(script);
}
context.Database.ExecuteSqlCommand(script);
}
}
else
{
Console.WriteLine("No pending migrations.");
}
}
else
{
Console.WriteLine("Database compatible with model.");
}
Application configuration:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 --></configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
<connectionStrings>
<add name="MyDbContext" connectionString="Data Source=.;Initial Catalog=MyDb;Integrated Security=true" providerName="System.Data.SqlClient" />
</connectionStrings>
</configuration>
Details about SQL Server and application:
- SQL Server version: 12.0.5563.0
- .NET version: 4.7.2