Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EntityFramework Code first migrations not running after deploying to Azure

I'm developing a web application in ASP.NET using code first migrations. It works fine locally but after deploying to Azure, code first migrations are not executed. I have been following this tutorial step by step a few times but I have not been able to spot what is wrong on my setup. Here is the relevant code:

DB Context:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext() : base("DefaultConnection", throwIfV1Schema: false) {}

    public DbSet<BC_Instance> BiocloudInstances { get; set; }

    static ApplicationDbContext() {}

    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        var conv = new AttributeToTableAnnotationConvention<SoftDeleteAttribute, string>(
           "SoftDeleteColumnName",
           (type, attributes) => attributes.Single().ColumnName);

        modelBuilder.Conventions.Add(conv);
    }
}

Connection strings:

(it is replaced on publish, but just in case)

<add name="DefaultConnection" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=bcplatform2;Integrated Security=True;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" /></connectionStrings>

Code First Migrations configuration

internal sealed class Configuration : DbMigrationsConfiguration<bcplatform2.Models.ApplicationDbContext>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = false;
    }

    protected override void Seed(bcplatform2.Models.ApplicationDbContext context)
    {
        var userManager = new ApplicationUserManager(new UserStore<ApplicationUser>(context));
        var roleManager = new ApplicationRoleManager(new RoleStore<ApplicationRole>(context));
        const string name = {name here};
        const string password = {pass here};
        const string adminRole = {role};
        string[] roles = new string[] { adminRole, ApplicationRole.DefaultRoleName };

        foreach (string role in roles)
        {
            if (!context.Roles.Any(r => r.Name == role))
            {
                roleManager.CreateAsync(new ApplicationRole(role));
            }
        }

        if (!context.Users.Any(u => u.UserName == name))
        {
            var user = new ApplicationUser { UserName = name, Email = name, credit = 10 };

            userManager.Create(user, password);
            userManager.AddToRole(user.Id, adminRole);
            userManager.SetLockoutEnabled(user.Id, false);
        }
    }
}

Publication wizard enter image description here

Entity framework section in deployed Web.config

<entityFramework>
  <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
    <parameters>
      <parameter value="mssqllocaldb" />
    </parameters>
  </defaultConnectionFactory>
  <providers>
    <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
  </providers>
  <contexts>
    <context type="bcplatform2.Models.ApplicationDbContext, bcplatform2">
      <databaseInitializer type="System.Data.Entity.MigrateDatabaseToLatestVersion`2[[bcplatform2.Models.ApplicationDbContext, bcplatform2], [bcplatform2.Migrations.Configuration, bcplatform2]], EntityFramework, PublicKeyToken={token}">
        <parameters>
          <parameter value="DefaultConnection_DatabasePublish" />
        </parameters>
      </databaseInitializer>
    </context>
  </contexts>
</entityFramework>

Connection strings in deployed Web.config

<connectionStrings>
  <add name="DefaultConnection" connectionString="Data Source=tcp:{serverid}.database.windows.net,1433;Initial Catalog={dbid};User Id={user};Password={password}" providerName="System.Data.SqlClient" />
  <add name="DefaultConnection_DatabasePublish" connectionString="Data Source=tcp:{serverid}.database.windows.net,1433;Initial Catalog={dbid};User ID={user};Password={password}" providerName="System.Data.SqlClient" />
</connectionStrings>
like image 781
nest Avatar asked Feb 05 '16 14:02

nest


People also ask

What is code first migrations in azure?

In this tutorial, you enable Code First migrations and deploy the application to the cloud in Azure: Enable Code First Migrations. The Migrations feature enables you to change the data model and deploy your changes to production by updating the database schema without having to drop and re-create the database.

How do I deploy a code first database to Azure web?

To deploy a Code First database to an Azure Web Site, you can use the Execute Code First Migrations check box in the Publish Web wizard:

How do I deploy a database using code first migrations?

Use Code First migrations to deploy the database. To deploy the database, you'll use Code First Migrations. When you create the publish profile that you use to configure settings for deploying from Visual Studio, you'll select a check box labeled Update Database.

How does entityframeworkcore create the database?

For every migration, EntityFrameworkCore adds a file to the Migrations folder. It contains a script that creates the database: When this script is executed it will create the following table structure: The table structure created when the migration script has executed.


3 Answers

You can update your Web.config file in Solution

It's not necessary provide connection string inside "context" section, because you already provide it in ApplicationDbContext constructor.

Also, with this config, you can uncheck "Execute code first migration" in Publication Wizard.

Your EF section should look similar to this (most important is "context" section):

<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
  <parameters>
    <parameter value="mssqllocaldb" />
  </parameters>
</defaultConnectionFactory>
<providers>
  <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
<contexts>
  <context type="TestWebApp.Models.AppContext, TestWebApp">
    <databaseInitializer type="System.Data.Entity.MigrateDatabaseToLatestVersion`2[[TestWebApp.Models.AppContext, TestWebApp], [TestWebApp.Migrations.Configuration, TestWebApp]], EntityFramework" />
  </context>
</contexts>

like image 169
Vadim Sentiaev Avatar answered Nov 07 '22 23:11

Vadim Sentiaev


It is not working because you might have created/selected other connection in deploy wizard. Same is confirmed in the deployed connection string where you can see two connnection strings.

The second connection string is also referecened in EF seciton -

And, in the context you have used first connectionstring - public ApplicationDbContext() : base("DefaultConnection", throwIfV1Schema: false) {}

Changing name here will solve your issue.

like image 34
jitendra singh Avatar answered Nov 07 '22 23:11

jitendra singh


if you want to have more control on the migration process you can handle the migration in the Startup.Auth by creating the context and use the DBMigrator() class to apply any pending migration:

//Get the connection string
var connectionString = ConfigurationManager.ConnectionStrings["DefaultConnection"];

//Instanciate the sql connection string builder
var builder = new System.Data.SqlClient.SqlConnectionStringBuilder(connectionString.ConnectionString);

//Create your context
var dbContext = new ApplicationDbContext(builder.ConnectionString);

//Check for null (Handle issue here).
if (dbContext == null) return;

//Get your configuration and specify the target database
var config = new Migrations.Configuration();
config.TargetDatabase = new DbConnectionInfo(builder.ConnectionString, "System.Data.SqlClient");

//Create the migrator using your config
var mig = new DbMigrator(config);

//Check for any pending migration to speed up the process and Update
//The migration will be applied here each time the application is published on azure   
if(mig.GetPendingMigrations().Any())mig.Update();

While this may not solve your issue directly, it allow more control and you should be able to see if the migration is not applied with a little debbuging.

like image 31
GaelSa Avatar answered Nov 07 '22 23:11

GaelSa