核心 2.2 中的项目
我有两个继承
IdentityUser
的类,其中第一个
public class DeveloperModel : IdentityUser
{
[Required(AllowEmptyStrings = false)]
public string FirstName { get; set; }
[Required(AllowEmptyStrings = false)]
public string SecondName { get; set; }
[Required(AllowEmptyStrings = false)]
public string Company { get; set; }
[Required(AllowEmptyStrings = false)]
public string CompanyName { get; set; }
[Required(AllowEmptyStrings = false)]
public string CompanyAdress { get; set; }
[Required(AllowEmptyStrings = false)]
public string CompanyEmail { get; set; }
[Required(AllowEmptyStrings = false)]
public string CompanyPhoneNumber { get; set; }
}
还有第二个
public class UserModel : IdentityUser
{
[Required(AllowEmptyStrings = false)]
public string FirstName { get; set; }
[Required(AllowEmptyStrings = false)]
public string SecondName { get; set; }
}
我对这两个课程的背景
public class EFDbContext : IdentityDbContext
{
public EFDbContext(DbContextOptions<EFDbContext> options) : base(options)
{
}
public DbSet<UserModel> UserModels { get; set; }
public DbSet<DeveloperModel> DeveloperModels { get; set; }
}
对于迁移的结束,我认为
[Id]
,[UserName]
,[NormalizedUserName]
,[Email]
,[NormalizedEmail]
,[EmailConfirmed]
,[PasswordHash]
,[SecurityStamp]
,[ConcurrencyStamp]
,[PhoneNumber]
,[PhoneNumberConfirmed]
,[TwoFactorEnabled]
,[LockoutEnd]
,[LockoutEnabled]
,[AccessFailedCount]
,[FirstName]
,[SecondName]
,[Company]
,[CompanyAdress]
,[CompanyEmail]
,[CompanyName]
,[CompanyPhoneNumber]
,**[UserModel_FirstName]**
,**[UserModel_SecondName]**
,[Discriminator]
我用 ** ** 标记来显示问题,在 .Net 继承的通常规则中,我为这两个类使用 1 个表。但是,我可以为每个类创建两个具有 IdentityUser 属性的表吗?
对于我的任务,我需要两张桌子。我不知道如何实现我的想法
我认为你必须用你的自定义模型注入你的
IdentityDbContext
。
您可以将您的模型映射到相应的表。 示例
builder.Entity<UserModel>(b =>
{
// Primary key
b.HasKey(u => u.Id);
//map properties
b.Property(u => u.FirstName ).HasName("FirstName").IsUnique();
b.Property(u => u.SecondName ).HasName("SecondName");
// Maps to the AspNetUsers table
b.ToTable("AspNetUsers");
});
builder.Entity<UserModelSplit>(b =>
{
// Primary key
b.HasKey(u => u.Id);
//map properties
b.Property(u => u.UserName ).HasName("UserName").IsUnique();
b.Property(u => u.NormalizedUserName ).HasName("NormalizedUserName");
...
...
...
// Maps to the AspNetUsers table
b.ToTable("AspNetUsersSplit");
});
public class EFDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, string>
{
public EFDbContext (DbContextOptions<EFDbContext > options) : base(options)
{
}
}
示例
public class ApplicationUser : IdentityUser
public class Instructor : ApplicationUser
public class Student : ApplicationUser
默认情况下,Entity Framework 将为 ApplicationUser 创建一张表,并向其中添加一个 Discriminator 列。此列将具有三个可能值之一:“ApplicationUser”、“Instructor”和“Student”。当 EF 从此表中读取数据时,它将使用该列来实例化正确的类。这就是所谓的单表继承 (STI) 或每层次结构表 (TPH)。这种方法的主要缺点是所有类的所有属性都必须在同一个表上表示。例如,如果您要创建新的学生,则教师的列仍将保留在记录中,只是这些值包含空值或默认值。这也意味着您无法在数据库级别强制要求 Instructor 等属性,因为这会阻止保存无法提供这些值的 ApplicationUser 和 Student 实例。换句话说,派生类的所有属性都必须可为空。但是,您仍然可以始终强制使用视图模型来强制执行诸如表单所需的属性之类的操作。
如果您确实想要拥有单独的表,则可以通过将继承策略更改为所谓的“每种类型一个表”(TPT) 来实现该目标。这样做的目的是保留 ApplicationUser 表,但添加两个附加表,教师和学生各一个。但是,所有核心属性、外键等都将出现在 ApplicationUser 的表中,因为这是定义这些属性的地方。教师和学生的表将仅包含在这些类上定义的属性(如果有)以及 ApplicationUser 表的外键。查询时,EF 将进行联接以引入所有这些表中的数据,并使用适当的数据实例化适当的类。一些纯粹主义者更喜欢这种方法,因为它可以使数据库中的数据保持标准化。然而,由于连接的原因,它在查询端必然会更重。
最后一句警告,因为这会让人们在不断处理带有身份的继承时陷入困境。 UserManager 类是一个泛型类(UserManager)。例如,AccountController 中的默认实例是 UserManager 的实例。因此,如果您使用该实例,则从查询返回的所有用户都将是 ApplicationUser 实例,无论 Discriminator 列的值如何。要获取讲师实例,您需要实例化 UserManager 并将其用于与讲师相关的查询。