迁移到Asp.Net Identity 2.0:AspNetUsers表中未创建新列

12

当我尝试在默认MVC 5应用中使用Identity 2.0注册新用户时,出现以下错误:

Invalid column name 'Email'.
Invalid column name 'EmailConfirmed'.
Invalid column name 'PhoneNumber'.
Invalid column name 'PhoneNumberConfirmed'.
Invalid column name 'TwoFactorEnabled'.
Invalid column name 'LockoutEndDateUtc'.
Invalid column name 'LockoutEnabled'.
Invalid column name 'AccessFailedCount'.
(repeats 2 more times, I have a total of 4 test users in AspNetUsers table.)

我有一个小应用程序,我刚刚将其从MVC4 / Identity 1.0升级到了MVC5 / Identity 2.0,所以我已经使Identity 1.0列(UserName、PasswordHash、SecurityStamp、Discriminator)工作。

  • 我使用标准的Identity 1.0表格在远程托管的SQL2012数据库上运行。
  • 我创建了一个“清洁”的项目,在localDB上注册用户,它可以正常运行。
  • 我成功在远程数据库上运行了“add-migration initial”和“update-database”命令。
  • 我最初遵循此官方指南,但第5步中的代码未被生成。我试图手动粘贴它,并再次运行了“update-database -verbose”命令。看起来成功完成,但仍然出现错误。

感谢任何帮助!

migration and configuration.cs文件

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

    protected override void Seed(FactBanker.Models.ApplicationDbContext context)
    {

    }
}

我的 V023 migration.cs 文件 无论是 Up() 还是 Down() 方法都是空的。

public partial class V023 : DbMigration
{
    public override void Up()
    {

    }

    public override void Down()
    {

    }
}

你所提到的指南并没有完整的迁移信息,其中缺少多个列... 当你运行 add-migration 命令时,它是否创建了迁移脚本?你能分享一下你的 configuration.cs[whatever]_initial.cs 文件吗? - dima
知道这点很好,谢谢。我已经添加了提到的文件,并正在寻找描述完整Identity 2.0模式的内容。 - Jason
你在运行 add-migration 和 update-database 命令之前,尝试关闭自动迁移 AutomaticMigrationsEnabled = false 了吗? - dima
是的,我后来确实将其更改为true。我只是将其更改为false,然后再次运行add-migration/update-database,结果相同。感谢您的建议。 - Jason
7个回答

12

我曾经遇到同样的问题。我使用了这个手动迁移方法,目前还没有遇到任何额外的问题。

public override void Up()
{
    RenameColumn(table: "dbo.AspNetUserClaims", name: "User_Id", newName: "UserId");
    RenameIndex(table: "dbo.AspNetUserClaims", name: "IX_User_Id", newName: "IX_UserId");
    DropPrimaryKey("dbo.AspNetUserLogins");
    AddColumn("dbo.AspNetUsers", "Email", c => c.String(maxLength: 256));
    AddColumn("dbo.AspNetUsers", "EmailConfirmed", c => c.Boolean(nullable: false));
    AddColumn("dbo.AspNetUsers", "PhoneNumber", c => c.String()); 
    AddColumn("dbo.AspNetUsers", "PhoneNumberConfirmed", c => c.Boolean(nullable: false));
    AddColumn("dbo.AspNetUsers", "TwoFactorEnabled", c => c.Boolean(nullable: false));
    AddColumn("dbo.AspNetUsers", "LockoutEndDateUtc", c => c.DateTime());
    AddColumn("dbo.AspNetUsers", "LockoutEnabled", c => c.Boolean(nullable: false));
    AddColumn("dbo.AspNetUsers", "AccessFailedCount", c => c.Int(nullable: false));
    AlterColumn("dbo.AspNetUsers", "UserName", c => c.String(nullable: false, maxLength: 256));
    AlterColumn("dbo.AspNetUsers", "FirstName", c => c.String(nullable: false));
    AlterColumn("dbo.AspNetUsers", "LastName", c => c.String(nullable: false));
    AddColumn("dbo.AspNetUsers", "CreatedDateTime", c => c.DateTime(nullable: false));
    AlterColumn("dbo.AspNetRoles", "Name", c => c.String(nullable: false, maxLength: 256));
    AddPrimaryKey("dbo.AspNetUserLogins", new[] { "LoginProvider", "ProviderKey", "UserId" });
    CreateIndex("dbo.AspNetUsers", "UserName", unique: true, name: "UserNameIndex");
    CreateIndex("dbo.AspNetRoles", "Name", unique: true, name: "RoleNameIndex");
    DropColumn("dbo.AspNetUsers", "Discriminator");
} 

Taken from: http://adamstephensen.com/2014/05/02/upgrading-from-asp-net-identity-1-0-to-2-0/


我认为这可能是最接近的答案,因为我已经改变了整体方法(完全摆脱了EF),所以还没有尝试过。但它看起来很不错,谢谢。 - Jason

4

原因是您已升级到Microsoft.AspNet.Identity.EntityFramework 2.0.0.0,这会更改用户上下文。

要解决问题,可以生成一个新的数据库(设置新的连接字符串mdf文件),或更改SQL表格。


1
感谢回复。这是一个相当好的问题概述。如果我手动更改表,我认为这并不能解决问题。使用add-migration/update-database应该会更改表,这是Code-First Entity Framework的重点。我会将其标记为答案,因为这是我看到的最接近的答案,现在我尝试的答案是完全放弃EF,并通过实现自己的IUserStore来实现自己的数据访问层,http://odetocode.com/blogs/scott/archive/2013/11/25/asp-net-core-identity.aspx - Jason
相关文章在此:http://jskiles1.wordpress.com/2014/04/20/upgrading-an-existing-project-from-asp-net-identity-1-0-to-2-0/ - GibboK
除了Dan Gershony的答案之外,我还添加了一个空的新数据库到SQL中,并将连接字符串指向这个新数据库。运行add-migration/Update-database来构建Identity 2.0的aspNet表。然后根据生成的更改更新我的正常开发数据库的新列/名称。最终成功登录,进行身份验证等操作。 - callisto

3

我曾面临同样的问题。根据Dan Gershony所说,我简单地卸载了 Microsoft.AspNet.Identity.EntityFramework2.0.0.0,并安装了一个较旧的版本,例如Microsoft.AspNet.Identity.EntityFramework -Version 1.0.0。这解决了我的问题。


这总是取决于您的需求,但请记住2.0修复了很多问题。 - Stephan Ahlf

2

尝试了user1502551提出的解决方案,但是它给我带来了问题,并且没有包括Down()方法。我遇到的问题是默认情况下Identity 1.0中不存在被更改的索引,并且2.0/2.1有一些额外的列是不需要的(即名字和姓氏字段)。完整的Up()和Down()代码如下:

public override void Up()
    {
        RenameColumn(table: "dbo.AspNetUserClaims", name: "User_Id", newName: "UserId");
        AddColumn("dbo.AspNetUsers", "Email", c => c.String());
        AddColumn("dbo.AspNetUsers", "EmailConfirmed", c => c.Boolean(nullable: false));
        AddColumn("dbo.AspNetUsers", "PhoneNumber", c => c.String());
        AddColumn("dbo.AspNetUsers", "PhoneNumberConfirmed", c => c.Boolean(nullable: false));
        AddColumn("dbo.AspNetUsers", "TwoFactorEnabled", c => c.Boolean(nullable: false));
        AddColumn("dbo.AspNetUsers", "LockoutEndDateUtc", c => c.DateTime());
        AddColumn("dbo.AspNetUsers", "LockoutEnabled", c => c.Boolean(nullable: false));
        AddColumn("dbo.AspNetUsers", "AccessFailedCount", c => c.Int(nullable: false));
        AlterColumn("dbo.AspNetUsers", "UserName", c => c.String(nullable: false));
        DropColumn("dbo.AspNetUsers", "Discriminator");
    }

    public override void Down()
    {
        AddColumn("dbo.AspNetUsers", "Discriminator", c => c.String(nullable: false, maxLength: 128));
        AlterColumn("dbo.AspNetUsers", "UserName", c => c.String(nullable: true));
        DropColumn("dbo.AspNetUsers", "AccessFailedCount");
        DropColumn("dbo.AspNetUsers", "LockoutEnabled");
        DropColumn("dbo.AspNetUsers", "LockoutEndDateUtc");
        DropColumn("dbo.AspNetUsers", "TwoFactorEnabled");
        DropColumn("dbo.AspNetUsers", "PhoneNumberConfirmed");
        DropColumn("dbo.AspNetUsers", "PhoneNumber");
        DropColumn("dbo.AspNetUsers", "EmailConfirmed");
        DropColumn("dbo.AspNetUsers", "Email");
        RenameColumn(table: "dbo.AspNetUserClaims", name: "UserId", newName: "User_Id");
    }

1
你需要修改所有在2.0版本中已更新的实体,例如:
public partial class AspNetUser
{    
    public AspNetUser()
    {
        AspNetUserClaims = new HashSet<AspNetUserClaim>();
        AspNetUserLogins = new HashSet<AspNetUserLogin>();
        AspNetRoles = new HashSet<AspNetRole>();
    }

    public string Id { get; set; }

    [StringLength(256)]
    public string UserName { get; set; }

    public string PasswordHash { get; set; }

    public string SecurityStamp { get; set; }

    [MaxLength(256)]
    public string Email { get; set; }

    public bool EmailConfirmed { get; set; }

    public string PhoneNumber { get; set; }

    public bool PhoneNumberConfirmed { get; set; }

    public bool TwoFactorEnabled { get; set; }

    public DateTime LockoutEndDateUtc { get; set; }

    public bool LockoutEnabled { get; set; }

    public int AccessFailedCount { get; set; }

    public int UserId { get; set; }

    public virtual ICollection<AspNetUserClaim> AspNetUserClaims { get; set; }

    public virtual ICollection<AspNetUserLogin> AspNetUserLogins { get; set; }

    public virtual User User { get; set; }

    public virtual ICollection<AspNetRole> AspNetRoles { get; set; }
}

public partial class AspNetUserClaim
{
    [Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public string ClaimType { get; set; }

    public string ClaimValue { get; set; }

    [Required]
    [StringLength(128)]
    public string UserId { get; set; }

    public virtual AspNetUser AspNetUser { get; set; }
}

你还需要修改在dbcontext的OnModelCreating方法中发生变化的实体映射,然后才能添加迁移。

谢谢。自那时起,我已经转移到了Azure B2C,所以无法测试答案,但希望它能帮助其他人。 - Jason

0

我遇到了同样的错误。我所做的就是在AspNetUser中手动添加LockoutEndDateUtc列。


0
你确定在你的Dbcontext中使用了正确的User类吗?如果你想要修改你的User表,你应该像这样继承它:
public class ApplicationDbContext : IdentityDbContext<MyCustomUserClass>
{
    ...
}

不要加任何像这样的东西:

public DbSet<MyCustomUserClass> Users { get; set; }

因为它已经在基类中发生了,所以在那里。


感谢您的想法,但是我没有修改或添加任何用户类。我与初始启动应用程序唯一的区别是我的数据库有额外的表,这些表引用了aspnetusers表中的Id列作为外键。我从这些表中删除了FK约束,并再次运行了迁移/更新,但没有任何变化。 - Jason

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