EntityFramework 部署到 Azure 后,代码优先迁移不是 运行
EntityFramework Code first migrations not running after deploying to Azure
我正在 ASP.NET 使用代码优先迁移开发 Web 应用程序。它在本地运行良好,但在部署到 Azure 后,不会执行代码优先迁移。我已经按照 this tutorial 的步骤进行了几次,但我无法发现我的设置有什么问题。这是相关代码:
数据库上下文:
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);
}
}
连接字符串:
(在发布时被替换,但以防万一)
<add name="DefaultConnection" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=bcplatform2;Integrated Security=True;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" /></connectionStrings>
Code First 迁移配置
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);
}
}
}
发布向导
Entity framework 部分已部署 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>
已部署的连接字符串 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>
您可以在解决方案
中更新您的Web.config文件
没有必要在 "context" 部分提供连接字符串,因为您已经在 ApplicationDbContext 构造函数中提供了它。
此外,使用此配置,您可以在发布向导中取消选中 "Execute code first migration"。
您的 EF 部分应该类似于此(最重要的是 "context" 部分 ):
<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>
它不起作用,因为您可能在部署向导中有 created/selected 其他连接。在部署的连接字符串中确认了同样的情况,您可以在其中看到两个连接字符串。
第二个连接字符串也在 EF 部分中被引用 -
并且,在您使用第一个连接字符串的上下文中 - public ApplicationDbContext() : base("DefaultConnection", throwIfV1Schema: false) {}
在这里更改名称将解决您的问题。
如果您想对迁移过程有更多的控制,您可以在 Startup.Auth 中处理迁移,方法是创建上下文并使用 DBMigrator() class 应用任何挂起的迁移:
//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();
虽然这可能无法直接解决您的问题,但它允许更多控制,您应该能够通过一些调试来查看迁移是否未应用。
问题出在种子方法上:
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);
}
}
它没有完成,但没有在发布输出中显示任何错误,因此很难发现错误。我删除了种子方法并且迁移成功了。
避免将来出现类似问题的一些建议是不要使用发布向导中的 "Use this connection string at runtime" 和 "Execute code first migrations" 选项。如果出现问题,输出不会总是显示错误,并且它几乎无法控制 Web.config 的修改方式。
相反,在发布之前替换 Web.config 中的连接字符串,或者相应地配置 Web.Debug.config 和 Web.Release.config。
我正在 ASP.NET 使用代码优先迁移开发 Web 应用程序。它在本地运行良好,但在部署到 Azure 后,不会执行代码优先迁移。我已经按照 this tutorial 的步骤进行了几次,但我无法发现我的设置有什么问题。这是相关代码:
数据库上下文:
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);
}
}
连接字符串:
(在发布时被替换,但以防万一)
<add name="DefaultConnection" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=bcplatform2;Integrated Security=True;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" /></connectionStrings>
Code First 迁移配置
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);
}
}
}
发布向导
Entity framework 部分已部署 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>
已部署的连接字符串 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>
您可以在解决方案
中更新您的Web.config文件没有必要在 "context" 部分提供连接字符串,因为您已经在 ApplicationDbContext 构造函数中提供了它。
此外,使用此配置,您可以在发布向导中取消选中 "Execute code first migration"。
您的 EF 部分应该类似于此(最重要的是 "context" 部分 ):
<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>
它不起作用,因为您可能在部署向导中有 created/selected 其他连接。在部署的连接字符串中确认了同样的情况,您可以在其中看到两个连接字符串。
第二个连接字符串也在 EF 部分中被引用 -
并且,在您使用第一个连接字符串的上下文中 - public ApplicationDbContext() : base("DefaultConnection", throwIfV1Schema: false) {}
在这里更改名称将解决您的问题。
如果您想对迁移过程有更多的控制,您可以在 Startup.Auth 中处理迁移,方法是创建上下文并使用 DBMigrator() class 应用任何挂起的迁移:
//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();
虽然这可能无法直接解决您的问题,但它允许更多控制,您应该能够通过一些调试来查看迁移是否未应用。
问题出在种子方法上:
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);
}
}
它没有完成,但没有在发布输出中显示任何错误,因此很难发现错误。我删除了种子方法并且迁移成功了。
避免将来出现类似问题的一些建议是不要使用发布向导中的 "Use this connection string at runtime" 和 "Execute code first migrations" 选项。如果出现问题,输出不会总是显示错误,并且它几乎无法控制 Web.config 的修改方式。
相反,在发布之前替换 Web.config 中的连接字符串,或者相应地配置 Web.Debug.config 和 Web.Release.config。