实体框架Code First迁移在部署到Azure后无法运行

7
我是一名有用的助手,可以为您翻译文本。

我正在使用ASP.NET进行编码优先迁移开发Web应用程序。在本地工作正常,但部署到Azure后,编码优先迁移未执行。我已经按照此教程多次逐步操作,但我没有能够发现我的设置有什么问题。以下是相关代码:

DB上下文:

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 Migrations配置

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);
        }
    }
}

发布向导 在此输入图像描述

已部署的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 文件吗? - ErikEJ
不,但是与数据库的连接不是问题所在。问题在于迁移没有应用,也没有进行数据库种子填充。我会查一下的。 - nest
@ErikEJ 我修改了问题,包括这些信息。实际上,我不确定在 <parameter value="mssqllocaldb" /><databaseInitializer type="System.Data.Entity.MigrateDatabaseToLatestVersion\2` 这里是否正确。你知道应该是这样吗? - nest
1
尝试从“databaseInitializer”中删除“parameters”部分。或者检查Azure网站配置中是否存在连接字符串“DefaultConnection_DatabasePublish”。 - Vadim Sentiaev
通过网站配置,您指的是web.config文件吗?如果是的话,它已经存在,并且有一个名为DefaultConnection的内容完全相同的部分。至于删除parameters部分,我不知道如何操作,因为它是在部署过程中生成的代码,不在VisualStudio项目中。谢谢。 - nest
显示剩余3条评论
4个回答

7

您可以在解决方案中更新Web.config文件。

在"context"部分内提供连接字符串并不是必需的,因为您已经在ApplicationDbContext构造函数中提供了它。

此外,使用此配置,您可以在发布向导中取消选择"执行代码优先迁移"。

您的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>


2

不起作用的原因可能是您在部署向导中创建或选择了其他连接。在已部署的连接字符串中确认了这一点,您可以看到两个连接字符串。

第二个连接字符串也在 EF 部分引用 -

而在您使用第一个连接字符串的上下文中 - public ApplicationDbContext() : base("DefaultConnection", throwIfV1Schema: false) {}

在此更改名称将解决您的问题。


谢谢@jitendra。这很有道理。但是你知道我怎么才能摆脱这个“其他”连接吗?事实上,在部署过程中,它是由系统自动创建的。我想在开发和生产环境中都使用“DefaultConnection”。 - nest
尝试在部署向导中取消勾选“使用此连接字符串”选项,因为您已经有一个。这可能会有所帮助。 - jitendra singh
你解决了吗?我很想听听反馈。 - jitendra singh

1
如果您希望更加控制迁移过程,可以在 Startup.Auth 中创建上下文,并使用 DBMigrator() 类来应用任何待处理的迁移。
//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();

虽然这可能不能直接解决您的问题,但它可以提供更多控制,并且您应该能够通过一些调试来查看是否未应用迁移。

1
问题出在种子方法上:
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);
    }
}

它没有完成,但在发布输出中没有显示任何错误,使得错误难以发现。我删除了种子方法,迁移工作正常。

为了避免类似问题,建议不要使用发布向导中的“在运行时使用此连接字符串”和“执行代码优先迁移”选项。如果出现问题,输出不会总是显示错误,并且对于如何修改 Web.config 的控制很少。

相反,在发布之前替换 Web.config 中的连接字符串或者相应地配置 Web.Debug.config 和 Web.Release.config。


是的,但我不知道它有什么问题,因为相同的代码在“后期阶段”成功完成,但在种子操作上失败了。 - nest

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接