How to use TPH (Table Per Hierarchy) with ASP.NET Identity 2
我在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | public class Student : ApplicationUser { public int? Number { get; set; } } public class Coordinator : ApplicationUser { public string Room { get; set; } } public class ApplicationUser : IdentityUser<int, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>, IUser<int> { //Custom Properties public string Name { get; set; } public string Surname { get; set; } //code omitted for brevity } |
由于
1 | public DbSet<ApplicationUser> ApplicationUsers { get; set; } |
另一方面,还有另一个实体具有 Student(不是 ApplicationUser)作为导航属性,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public class Grade { [Key] public int Id { get; set; } public int Grade { get; set; } //Navigation properties =========================== public virtual Experiment Experiment { get; set; } public virtual Student Student { get; set; } //public virtual ApplicationUser User { get; set; } //================================================= } |
}
但是,当将 DbSet 添加到
你应该可以在不添加
1 2 3 4 5 6 7 | public class ApplicationDbContext : IdentityDbContext<ApplicationUser> { public DbSet<Student> Students { get; set; } public DbSet<Coordinator> Coordinators { get; set; } public DbSet<Grade> Grades { get; set; } ... } |
在你的
检查您的数据库是否与您的模型同步。你在使用 EF 迁移吗?迁移文件中的表应如下所示:(注意
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | CreateTable( "dbo.AspNetUsers", c => new { Id = c.String(nullable: false, maxLength: 128), Name = c.String(), Surname = c.String(), Email = c.String(maxLength: 256), EmailConfirmed = c.Boolean(nullable: false), PasswordHash = c.String(), SecurityStamp = c.String(), PhoneNumber = c.String(), PhoneNumberConfirmed = c.Boolean(nullable: false), TwoFactorEnabled = c.Boolean(nullable: false), LockoutEndDateUtc = c.DateTime(), LockoutEnabled = c.Boolean(nullable: false), AccessFailedCount = c.Int(nullable: false), UserName = c.String(nullable: false, maxLength: 256), Room = c.String(), Number = c.Int(), Discriminator = c.String(nullable: false, maxLength: 128), }) .PrimaryKey(t => t.Id) .Index(t => t.UserName, unique: true, name:"UserNameIndex"); CreateTable( "dbo.Grades", c => new { Id = c.Int(nullable: false, identity: true), GradeValue = c.Int(nullable: false), Student_Id = c.String(maxLength: 128), }) .PrimaryKey(t => t.Id) .ForeignKey("dbo.AspNetUsers", t => t.Student_Id) .Index(t => t.Student_Id); |
如果您的表看起来不像这些,请尝试恢复到空数据库,删除迁移并再次生成它们,最后使用良好的迁移更新数据库。
我用您的实体和
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | public void Test() { using (var context = new ApplicationDbContext()) { var student = new Student { Id ="12345", Name ="John", Number = 123, UserName ="Johnny", Email ="[email protected]" }; context.Students.Add(student); context.SaveChanges(); } using (var context = new ApplicationDbContext()) { var student = context.Students.Find("12345"); var grade = new Grade { Id = 333, GradeValue = 90, Student = student }; context.Grades.Add(grade); context.SaveChanges(); } } |
一些问题:
-
"多个对象集"错误消息说明了"对象集\\'ApplicationUsers\\'和\\'Users\\'"。这个 \\'Users\\' 对象集来自哪里,你有一个用户
DbSet 吗?尝试删除它。或者您可能使用DbSet 的类型参数进行了复制粘贴错误,类似于编写public DbSet<wrongType> GoodTypeName (它发生了)。 -
我对这个声明有疑问:
1
2public class ApplicationUser : IdentityUser<int, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>, IUser<int>
{ ... }所以我用了这个(基类中没有类型参数):
1
2public class ApplicationUser : IdentityUser
{ ... }似乎带有 Identity 的 MVC 项目的默认实现期望
ApplicationUser 在没有类型参数的情况下扩展IdentityUser 的实现。否则会在多个地方出现编译错误,例如在声明ApplicationContext 并尝试使用ApplicationUser 作为基类IdentityDbContext 的类型参数时。 -
如果您使用带有类型参数的基类,我认为
TKey 类型参数应该是 String 而不是 int,除非您在自定义实体中更改了User.Id 属性类型。也许您因此而遇到错误?在数据库中,这些实体的 Id 字段的类型为 varchar. -
我将
Grade 属性的名称更改为GradeValue (Grade 不是有效的属性名称,因为它是类的名称,我遇到了编译错误)。
如果你需要它,我可以发送我用来测试这个的虚拟解决方案的代码。