我已经按照本论坛中的描述自定义了身份表名称和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);
});
}
答案 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