【问题标题】:Renaming Identity tables with EF6 Migrations Failing重命名 EF6 迁移失败的身份表
【发布时间】:2015-05-08 02:17:48
【问题描述】:

我正在尝试通过 EF6/包管理器中的迁移工具重命名我的 Identity 2.0 表。但是,它正在炸毁其中的一部分。我只是在 IdentityModels.cs 中的“ApplicationDBContext Create”之后调用以下代码:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            modelBuilder.Entity<IdentityUser>().ToTable("Users");
            modelBuilder.Entity<IdentityRole>().ToTable("Roles");
            modelBuilder.Entity<IdentityUserRole>().ToTable("UserRoles");
            modelBuilder.Entity<IdentityUserLogin>().ToTable("UserLogins");
            modelBuilder.Entity<IdentityUserClaim>().ToTable("UserClaims");
        }

然后它会报错:

PM> Update-Database -Verbose
Using StartUp project 'ProjectSender'.
Using NuGet project 'ProjectSender'.
Specify the '-Verbose' flag to view the SQL statements being applied to the target database.
Target database is: 'Projectsender' (DataSource: x.x.x.x, Provider: System.Data.SqlClient, Origin: Configuration).
Applying explicit migrations: [201505080059533_RenameTables].
Applying explicit migration: 201505080059533_RenameTables.
EXECUTE sp_rename @objname = N'dbo.AspNetRoles', @newname = N'Roles', @objtype = N'OBJECT'
IF object_id('[PK_dbo.AspNetRoles]') IS NOT NULL BEGIN
    EXECUTE sp_rename @objname = N'[PK_dbo.AspNetRoles]', @newname = N'PK_dbo.Roles', @objtype = N'OBJECT'
END
Caution: Changing any part of an object name could break scripts and stored procedures.
Caution: Changing any part of an object name could break scripts and stored procedures.
EXECUTE sp_rename @objname = N'dbo.AspNetUserRoles', @newname = N'UserRoles', @objtype = N'OBJECT'
IF object_id('[PK_dbo.AspNetUserRoles]') IS NOT NULL BEGIN
    EXECUTE sp_rename @objname = N'[PK_dbo.AspNetUserRoles]', @newname = N'PK_dbo.UserRoles', @objtype = N'OBJECT'
END
EXECUTE sp_rename @objname = N'dbo.AspNetUserClaims', @newname = N'UserClaims', @objtype = N'OBJECT'
IF object_id('[PK_dbo.AspNetUserClaims]') IS NOT NULL BEGIN
    EXECUTE sp_rename @objname = N'[PK_dbo.AspNetUserClaims]', @newname = N'PK_dbo.UserClaims', @objtype = N'OBJECT'
END
EXECUTE sp_rename @objname = N'dbo.AspNetUserLogins', @newname = N'UserLogins', @objtype = N'OBJECT'
IF object_id('[PK_dbo.AspNetUserLogins]') IS NOT NULL BEGIN
    EXECUTE sp_rename @objname = N'[PK_dbo.AspNetUserLogins]', @newname = N'PK_dbo.UserLogins', @objtype = N'OBJECT'
END
IF object_id(N'[dbo].[FK_dbo.AspNetUserClaims_dbo.AspNetUsers_UserId]', N'F') IS NOT NULL
    ALTER TABLE [dbo].[AspNetUserClaims] DROP CONSTRAINT [FK_dbo.AspNetUserClaims_dbo.AspNetUsers_UserId]
System.Data.SqlClient.SqlException (0x80131904): Cannot find the object "dbo.AspNetUserClaims" because it does not exist or you do not have permissions.
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
   at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
   at System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean async, Int32 timeout, Boolean asyncWrite)
   at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite)
   at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
   at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.<NonQuery>b__0(DbCommand t, DbCommandInterceptionContext`1 c)
   at System.Data.Entity.Infrastructure.Interception.InternalDispatcher`1.Dispatch[TTarget,TInterceptionContext,TResult](TTarget target, Func`3 operation, TInterceptionContext interceptionContext, Action`3 executing, Action`3 executed)
   at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.NonQuery(DbCommand command, DbCommandInterceptionContext interceptionContext)
   at System.Data.Entity.Internal.InterceptableDbCommand.ExecuteNonQuery()
   at System.Data.Entity.Migrations.DbMigrator.ExecuteSql(MigrationStatement migrationStatement, DbConnection connection, DbTransaction transaction, DbInterceptionContext interceptionContext)
   at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.ExecuteSql(MigrationStatement migrationStatement, DbConnection connection, DbTransaction transaction, DbInterceptionContext interceptionContext)
   at System.Data.Entity.Migrations.DbMigrator.ExecuteStatementsInternal(IEnumerable`1 migrationStatements, DbConnection connection, DbTransaction transaction, DbInterceptionContext interceptionContext)
   at System.Data.Entity.Migrations.DbMigrator.ExecuteStatementsWithinTransaction(IEnumerable`1 migrationStatements, DbTransaction transaction, DbInterceptionContext interceptionContext)
   at System.Data.Entity.Migrations.DbMigrator.ExecuteStatementsWithinNewTransaction(IEnumerable`1 migrationStatements, DbConnection connection, DbInterceptionContext interceptionContext)
   at System.Data.Entity.Migrations.DbMigrator.ExecuteStatementsInternal(IEnumerable`1 migrationStatements, DbConnection connection, DbInterceptionContext interceptionContext)
   at System.Data.Entity.Migrations.DbMigrator.ExecuteStatementsInternal(IEnumerable`1 migrationStatements, DbConnection connection)
   at System.Data.Entity.Migrations.DbMigrator.<>c__DisplayClass30.<ExecuteStatements>b__2e()
   at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.<>c__DisplayClass1.<Execute>b__0()
   at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
   at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute(Action operation)
   at System.Data.Entity.Migrations.DbMigrator.ExecuteStatements(IEnumerable`1 migrationStatements, DbTransaction existingTransaction)
   at System.Data.Entity.Migrations.DbMigrator.ExecuteStatements(IEnumerable`1 migrationStatements)
   at System.Data.Entity.Migrations.Infrastructure.MigratorBase.ExecuteStatements(IEnumerable`1 migrationStatements)
   at System.Data.Entity.Migrations.DbMigrator.ExecuteOperations(String migrationId, VersionedModel targetModel, IEnumerable`1 operations, IEnumerable`1 systemOperations, Boolean downgrading, Boolean auto)
   at System.Data.Entity.Migrations.DbMigrator.ApplyMigration(DbMigration migration, DbMigration lastMigration)
   at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.ApplyMigration(DbMigration migration, DbMigration lastMigration)
   at System.Data.Entity.Migrations.DbMigrator.Upgrade(IEnumerable`1 pendingMigrations, String targetMigrationId, String lastMigrationId)
   at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.Upgrade(IEnumerable`1 pendingMigrations, String targetMigrationId, String lastMigrationId)
   at System.Data.Entity.Migrations.DbMigrator.UpdateInternal(String targetMigration)
   at System.Data.Entity.Migrations.DbMigrator.<>c__DisplayClassc.<Update>b__b()
   at System.Data.Entity.Migrations.DbMigrator.EnsureDatabaseExists(Action mustSucceedToKeepDatabase)
   at System.Data.Entity.Migrations.Infrastructure.MigratorBase.EnsureDatabaseExists(Action mustSucceedToKeepDatabase)
   at System.Data.Entity.Migrations.DbMigrator.Update(String targetMigration)
   at System.Data.Entity.Migrations.Infrastructure.MigratorBase.Update(String targetMigration)
   at System.Data.Entity.Migrations.Design.ToolingFacade.UpdateRunner.Run()
   at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
   at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
   at System.Data.Entity.Migrations.Design.ToolingFacade.Run(BaseRunner runner)
   at System.Data.Entity.Migrations.Design.ToolingFacade.Update(String targetMigration, Boolean force)
   at System.Data.Entity.Migrations.UpdateDatabaseCommand.<>c__DisplayClass2.<.ctor>b__0()
   at System.Data.Entity.Migrations.MigrationsDomainCommand.Execute(Action command)
ClientConnectionId:c43cef2f-1614-40cc-a405-ecec90028871
Error Number:4902,State:1,Class:16
Cannot find the object "dbo.AspNetUserClaims" because it does not exist or you do not have permissions.

这是一个远程 SQL Server 2014 Express。但是,我暂时将我的 VS/sql 用户设置为 SysAdmin 以知道这不是权限问题....所有表都在那里,包括它似乎爆炸的 FK。

我很想只运行我从(在实际的 SQL 服务器上)获得的 sql 脚本:

Update-Database -Script

然后做一个:

Add-Migration InitialCreate –IgnoreChanges

但是,我担心我将不得不跳过其他错误和障碍。非常感谢任何帮助。

【问题讨论】:

  • 看起来您需要在重命名之前删除 FK 关系(然后使用新的表名重新应用它们)。 -- 虽然我认为 sp_rename 是为你做的......
  • 谢谢,是的,我很担心通过手动调整 SQL 来使 EF 迁移工具失控。我正在和这件事进行一场真正的战斗。但是,我认为它以错误的顺序创建 SQL 命令。所以,我最好的猜测是它在 AspNetUserClaims 表中看不到该约束,因为在它尝试删除该表的约束时,该表已被重命名为 UserClaims。因此,AspNetUserClaims“不存在”......这意味着我必须手动干预,因为我看不到解决办法......?
  • 您说您正在使用迁移,可以尝试修改该特定迁移(而不是使用 onModelCreating)然后应用更新数据库。
  • 好的,谢谢,我知道我现在在哪里可以做到这一点,并会试一试...我刚刚意识到 AspNetUsers 表的 sp_rename 等都丢失了。 . 然后它稍后在 sql/migration 代码中引用实际的“AspNetUsers”表。所以,我必须有那个身份映射不正确或什么的。无论如何,再次感谢,我会看看我是否无法解决问题并稍后再发回......
  • 祝你好运。但总的来说,我会说坚持将迁移保持在迁移类中。在创建模型时一次性使用是有好处的,但是当您查看多个增量时会变得复杂。

标签: sql-server asp.net-mvc entity-framework entity-framework-6


【解决方案1】:

OnModelCreating 是做这件事的地方,但你也想利用迁移来做这种事情。话虽如此,假设我们将更改添加到OnModelCreating 内的我们的“ApplicationDbContext”(使用默认项目名称):

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    modelBuilder.Entity<ApplicationUser>().ToTable("Users");
    modelBuilder.Entity<IdentityRole>().ToTable("Roles");
    modelBuilder.Entity<IdentityUserClaim>().ToTable("UserClaims");
    modelBuilder.Entity<IdentityUserLogin>().ToTable("UserLogins");
    modelBuilder.Entity<IdentityUserRole>().ToTable("UserRoles");
}

调用Add-Migration AspNetIdentity_RenameTables 应该会为我们生成迁移脚本(这假设存在现有迁移以使用默认命名创建身份表):

public partial class AspNetIdentity_RenameTables : DbMigration
{
    public override void Up()
    {
        RenameTable(name: "dbo.AspNetRoles", newName: "Roles");
        RenameTable(name: "dbo.AspNetUserRoles", newName: "UserRoles");
        RenameTable(name: "dbo.AspNetUsers", newName: "Users");
        RenameTable(name: "dbo.AspNetUserClaims", newName: "UserClaims");
        RenameTable(name: "dbo.AspNetUserLogins", newName: "UserLogins");
    }

    public override void Down()
    {
        RenameTable(name: "dbo.UserLogins", newName: "AspNetUserLogins");
        RenameTable(name: "dbo.UserClaims", newName: "AspNetUserClaims");
        RenameTable(name: "dbo.Users", newName: "AspNetUsers");
        RenameTable(name: "dbo.UserRoles", newName: "AspNetUserRoles");
        RenameTable(name: "dbo.Roles", newName: "AspNetRoles");
    }
}

现在调用Update-Database 会处理剩下的事情。显然,如果您使用 Migrate 初始化程序设置了 DbInitializer,这将在首次加载时为您完成。

现在,我们有了重命名的表:

可以在 GitHub 上找到一个示例(带有提交历史记录):https://github.com/bchristie/AspNetIdentity-RenameTables


增加一些清晰度:

OnModelCreating 有它的目的,那就是让 EF 了解关系、键、实体到表的关系等。EF 的迁移功能在更进一步和管理中间关系方面表现出色数据库的状态,所以我喜欢尽可能利用它。

鉴于 IdentityDbContext 内部有自己的声明,我们需要通过添加我们自己的 OnModelCreating 来超越它的配置(但只有在我们调用了基本方法之后)。现在我们有了所有现有的结构,但有了一个新名称。

引用您正在使用的实体也很重要。因此,由于默认项目使用ApplicationUser,这就是我们在modelBuilder.Entity&lt;&gt;() 中引用的内容。

【讨论】:

  • 写得很好,谢谢!所以,看起来我什至不需要 modelBuilder.Entity().ToTable("Users");行,这将避免 DropForeignKey 方法。我要从头开始,看看这次我能不能更顺利一点。我非常感谢您的帮助和信息。
【解决方案2】:

如果您阅读了上面的 cmets,这更像是一种变通方法,而不是实际的解决方案。

首先(与上述错误无关),重命名我的 AspNetUsers 表的部分代码丢失了,因此,我的 onModelCreating 函数中的必要行也是如此:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            modelBuilder.Entity<IdentityUser>().ToTable("Users");
            modelBuilder.Entity<ApplicationUser>().ToTable("Users"); //this line needed!!
            modelBuilder.Entity<IdentityRole>().ToTable("Roles");
            modelBuilder.Entity<IdentityUserRole>().ToTable("UserRoles");
            modelBuilder.Entity<IdentityUserLogin>().ToTable("UserLogins");
            modelBuilder.Entity<IdentityUserClaim>().ToTable("UserClaims");
        }

即使在更正后,必要的迁移代码仍以错误的顺序生成 SQL 代码,并且仍然抛出上述错误,在表已重命名后引用旧表名。因此,我不得不直接编辑迁移文件并将DropForeignKey 方法移到RenameTable 方法之前的顶部:

public override void Up()
        {
            DropForeignKey("dbo.AspNetUserClaims", "UserId", "dbo.AspNetUsers");
            DropForeignKey("dbo.AspNetUserLogins", "UserId", "dbo.AspNetUsers");
            DropForeignKey("dbo.AspNetUserRoles", "UserId", "dbo.AspNetUsers");
            RenameTable(name: "dbo.AspNetRoles", newName: "Roles");
            RenameTable(name: "dbo.AspNetUserRoles", newName: "UserRoles");
            RenameTable(name: "dbo.AspNetUsers", newName: "Users");
            RenameTable(name: "dbo.AspNetUserClaims", newName: "UserClaims");
            RenameTable(name: "dbo.AspNetUserLogins", newName: "UserLogins");
            DropIndex("dbo.UserRoles", new[] { "UserId" });
            DropIndex("dbo.UserClaims", new[] { "UserId" });
            DropIndex("dbo.UserLogins", new[] { "UserId" });
            AddColumn("dbo.UserRoles", "IdentityUser_Id", c => c.String(maxLength: 128));
            AddColumn("dbo.Users", "Discriminator", c => c.String(nullable: false, maxLength: 128));
            AddColumn("dbo.UserClaims", "IdentityUser_Id", c => c.String(maxLength: 128));
            AddColumn("dbo.UserLogins", "IdentityUser_Id", c => c.String(maxLength: 128));
            AlterColumn("dbo.UserClaims", "UserId", c => c.String());
            CreateIndex("dbo.UserRoles", "IdentityUser_Id");
            CreateIndex("dbo.UserClaims", "IdentityUser_Id");
            CreateIndex("dbo.UserLogins", "IdentityUser_Id");
            AddForeignKey("dbo.UserClaims", "IdentityUser_Id", "dbo.Users", "Id");
            AddForeignKey("dbo.UserLogins", "IdentityUser_Id", "dbo.Users", "Id");
            AddForeignKey("dbo.UserRoles", "IdentityUser_Id", "dbo.Users", "Id");
        }

在更改 Update-Database 后成功运行。

我在 www.asp.net/identity 上观看了这个过程的视频教程,并阅读了一些关于它的 google 线索,我真的不知道为什么我的错误而示例没有。我想我很幸运。但是,这是我的环境,以防万一它是一个错误:

  • MVC 5.2.3
  • EF 6.1.3
  • 身份 2.2.1
  • VS 2013
  • SQL Express 2014

关于下一个问题......很快再见......

【讨论】:

    【解决方案3】:

    首先。 在成功重命名默认 IdentityUser 表之前,将 ApplicationUser 类重命名为您希望的名称。

    因为 ApplicationUser 类继承自 IdentityUser 并且是您的应用程序实际直接引用的用户配置文件问题。 因此,如果不更改,使用与用户配置文件有关的 onModelCreating() 函数的表更改过程会给出参考、安全或关系错误。

    查找随附的更改屏幕截图以进一步了解我的观点。谢谢,希望能解决你的问题。

    // Note this class is what i changed from ApplicationUser to just User
    
    public class User : IdentityUser
        {
            public async Task<ClaimsIdentity> 
                GenerateUserIdentityAsync(UserManager<User> manager)
            {
                .......... codes
            }
        }
    
    
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                base.OnModelCreating(modelBuilder);
    
    
                base.OnModelCreating(modelBuilder);
    
                // Rather than identityUser generic class , use the name of the renamed ApplicationUser being User
                modelBuilder.Entity<User>().ToTable("User").Property(x => x.Id).HasColumnName("UserId");
    
                modelBuilder.Entity<IdentityUserRole>().ToTable("UserRole");
                modelBuilder.Entity<IdentityUserLogin>().ToTable("UserLogin");
    
                modelBuilder.Entity<IdentityUserClaim>().ToTable("UserClaim").Property(x => x.Id).HasColumnName("ClaimId");
                modelBuilder.Entity<IdentityRole>().ToTable("Role").Property(x => x.Id).HasColumnName("RoleId");
    
    
            }
    

    查找随附的更改屏幕截图以进一步了解我的观点。谢谢,希望能解决你的问题。

    【讨论】:

      猜你喜欢
      • 2018-08-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-10
      • 2014-03-02
      • 2014-12-23
      • 2012-08-09
      • 1970-01-01
      相关资源
      最近更新 更多