重命名Asp.Net MVC Core App中的身份表后,无法保存用户帐户

时间:2019-03-27 10:40:43

标签: asp.net-core entity-framework-6 asp.net-core-mvc

我已经按照本论坛中的描述自定义了身份表名称和IdentityUser。我的问题是,此后我无法保存用户帐户,并且出现以下错误:

  

不能将表App Users用于实体类型App Users,因为该表正用于实体类型ApplicationUser,并且它们的主键之间没有关系。

我在此处包括了一个可以从here下载的演示应用程序

自定义表名之后,我确实添加了迁移并更新了数据库,所有这些操作均成功完成,然后我使用dotnet ef dbcontext scaffold命令导入其他数据库表。此后,我添加了另一个失败的迁移,ef框架将错误抛出以下:

  

不能将表'AppRole'用于实体类型'AppRole',因为它已用于实体类型'IdentityRole',并且它们的主键之间没有关系。

我已重置迁移,删除了_migration表,然后重新开始,但无法正常工作。因此,我恳请您在这方面为我提供帮助。

这是数据库上下文的快照

protected override void OnModelCreating(ModelBuilder modelBuilder)

{
    base.OnModelCreating(modelBuilder);

    modelBuilder.HasAnnotation("ProductVersion", "2.2.3-servicing-35854");

    foreach (var entityType in modelBuilder.Model.GetEntityTypes())
    {
        var table = entityType.Relational().TableName;
        if (table.StartsWith("AspNet"))
        {
            entityType.Relational().TableName = table.Replace(table.Substring(0, 6), "App");
        }
    };

    modelBuilder.Entity<AppRoleClaims>(entity =>
    {
        entity.HasIndex(e => e.RoleId);

        entity.Property(e => e.RoleId).IsRequired();

        entity.HasOne(d => d.Role)
            .WithMany(p => p.AppRoleClaims)
            .HasForeignKey(d => d.RoleId);
    });

    modelBuilder.Entity<AppRoles>(entity =>
    {
        entity.HasIndex(e => e.NormalizedName)
            .HasName("RoleNameIndex")
            .IsUnique()
            .HasFilter("([NormalizedName] IS NOT NULL)");

        entity.Property(e => e.Id).ValueGeneratedNever();

        entity.Property(e => e.Name).HasMaxLength(256);

        entity.Property(e => e.NormalizedName).HasMaxLength(256);
    });

    modelBuilder.Entity<AppUserClaims>(entity =>
    {
        entity.HasIndex(e => e.UserId);

        entity.Property(e => e.UserId).IsRequired();

        entity.HasOne(d => d.User)
            .WithMany(p => p.AppUserClaims)
            .HasForeignKey(d => d.UserId);
    });

    modelBuilder.Entity<AppUserLogins>(entity =>
    {
        entity.HasKey(e => new { e.LoginProvider, e.ProviderKey });

        entity.HasIndex(e => e.UserId);

        entity.Property(e => e.LoginProvider).HasMaxLength(128);

        entity.Property(e => e.ProviderKey).HasMaxLength(128);

        entity.Property(e => e.UserId).IsRequired();

        entity.HasOne(d => d.User)
            .WithMany(p => p.AppUserLogins)
            .HasForeignKey(d => d.UserId);
    });

    modelBuilder.Entity<AppUserRoles>(entity =>
    {
        entity.HasKey(e => new { e.UserId, e.RoleId });

        entity.HasIndex(e => e.RoleId);

        entity.HasOne(d => d.Role)
            .WithMany(p => p.AppUserRoles)
            .HasForeignKey(d => d.RoleId);

        entity.HasOne(d => d.User)
            .WithMany(p => p.AppUserRoles)
            .HasForeignKey(d => d.UserId);
    });

    modelBuilder.Entity<AppUserTokens>(entity =>
    {
        entity.HasKey(e => new { e.UserId, e.LoginProvider, e.Name });

        entity.Property(e => e.LoginProvider).HasMaxLength(128);

        entity.Property(e => e.Name).HasMaxLength(128);

        entity.HasOne(d => d.User)
            .WithMany(p => p.AppUserTokens)
            .HasForeignKey(d => d.UserId);
    });

    modelBuilder.Entity<AppUsers>(entity =>
    {
        entity.HasIndex(e => e.NormalizedEmail)
            .HasName("EmailIndex");

        entity.HasIndex(e => e.NormalizedUserName)
            .HasName("UserNameIndex")
            .IsUnique()
            .HasFilter("([NormalizedUserName] IS NOT NULL)");

        entity.Property(e => e.Id).ValueGeneratedNever();

        entity.Property(e => e.Email).HasMaxLength(256);

        entity.Property(e => e.NormalizedEmail).HasMaxLength(256);

        entity.Property(e => e.NormalizedUserName).HasMaxLength(256);

        entity.Property(e => e.UserName).HasMaxLength(256);
    });
}

2 个答案:

答案 0 :(得分:1)

美好的一天,这是一条详细的指南,适用于希望使用Asp.Net Core 2.2和ef core将数据库优先用于自定义身份表的任何人。

步骤1 ==>首先创建数据库,然后添加所有表,关系和约束

步骤2 ==>假设您已添加所有ef框架依赖项,请转到Visual Studio并创建一个名为例如ApplicationUser的类,该类继承自IdentityUser,并在其中添加自定义字段。

步骤3 ==>配置您的数据库上下文类以使用ApplicationUser并在注册 AddDbContext 服务时在Startup.cs中执行相同操作,还使用OnModelCreating来自定义身份表名称 >。记住要调用base.OnModelCreating(modelBuilder)

步骤4 ==>添加一个迁移和更新数据库,这将在我们现有的数据库中生成身份表。

步骤5 ==>转至关系数据库管理系统(RDBMS),并验证是否已添加您的自定义标识表。如果是这样,请转到步骤6,否则请先解决问题,然后再继续

步骤6 ==>从powershell发出 dotnet ef dbcontext支架“连接字符串” Microsoft.EntityFrameworkCore.SqlServer -o模型/实体-f -c“ TempDbContext” 命令或使用该软件包的等效命令管理器控制台

步骤7 ==> 非常重要:查找在步骤3中已自定义名称的所有与身份表相关的实体。请确保这7个实体均从Identity继承并指定其主键类型,例如:

public partial class AppUsers : IdentityUser<string>{}
public partial class AppUserTokens : IdentityUserToken<string>{}
public partial class AppUserRoles : IdentityUserRole<string>{}
public partial class AppUserLogins : IdentityUserLogin<string>{}
public partial class AppUserClaims : IdentityUserClaim<string>{}
public partial class AppRoles : IdentityRole<string>{}
public partial class AppRoleClaims : IdentityRoleClaim<string>{}

此步骤转到初始DBContext类后,在startup.cs中的ConfigureServices中注册了一个,并将类签名更改为

public class ApplicationDbContext : IdentityDbContext<AppUsers, AppRoles, string, AppUserClaims, AppUserRoles, AppUserLogins, AppRoleClaims, AppUserTokens>

第8步:从第6步中由 scaffold 命令自动生成的临时 TempDBContext 复制OnModelCreating内部的所有DbSet和一切方法,并替换初始内容DBContext,或者您也可以将 TempDBContext 设置为主DBContext,但请记住要更新ConfigureServices。

第9步:将所有引用更新为 ApplicationUser ,并使它们指向 AppUsers ,将所有自定义字段从 ApplicationUser 复制到 AppUsers ,这样做的原因是 ApplicationUser 在数据库中没有要映射的引用表,而 AppUsers 有。

步骤10 ==>更新所有注入的视图和部分视图

@inject SignInManager<AppUsers> SignInManager
@inject UserManager<AppUsers> UserManager

使用 ApplicationUser 中的 AppUsers ,尤其是_LoginPartial.cshtml,您就完成了。您现在可以如下添加用户帐户:

var user = new AppUsers
                {
                    Id = Guid.NewGuid().ToString(),
                    UserName = "example@gmail.com",
                    Email = "example@gmail.com",
                    PhoneNumber = "0123456789",
                };

                var result = await userManager.CreateAsync(user, "Ex@mple88@gmail.com");

完成!!!进行一些代码清理并删除不再需要的任何文件和代码,这就是我成功使用自定义表名和数据库优先方法使Identity正常工作的方式。如果不遵循这些步骤,将导致我发布的错误以及其他许多错误。感谢您通读。

答案 1 :(得分:0)

您可以使用以下方法更改表名:

base.OnModelCreating(builder);

builder.Entity<UserProfile>().ToTable("UserProfile");
builder.Entity<UserProfile>().Property(up => up.Id).HasColumnName("UserId");
builder.Entity<UserRole>().ToTable("Role").Property(ur => ur.Id).HasColumnName("RoleId");
builder.Entity<UserRole>().Property(ur => ur.Id).HasColumnName("UserRoleId");
builder.Entity<IdentityUserClaim<int>>().ToTable("UserClaim");
builder.Entity<IdentityUserRole<int>>().ToTable("UserRole").HasKey(k => new {k.RoleId, k.UserId});
builder.Entity<IdentityUserLogin<int>>().ToTable("UserLogin");
builder.Entity<IdentityRoleClaim<int>>().ToTable("RoleClaim");
builder.Entity<IdentityUserToken<int>>().ToTable("UserToken");

参考: https://mitchelsellers.com/blogs/2017/09/05/taking-control-of-aspnet-identity-table-names