如何使用 IdentityUser 创建两个差异 table
How create two difference table with IdentityUser
核心 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 table。但是,我可以为每个 类 创建两个具有 identityUser 属性的 table 吗?
为了完成我的任务,我需要两个 table。我不知道如何实现我的想法
我认为您必须将 IdentityDbContext
与您的自定义模型一起注入。
您可以将模型映射到相应的 table。 example
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 创建一个 table 并向其添加鉴别器列。此列将具有三个可能值之一:"ApplicationUser"、"Instructor" 和 "Student"。当EF从这个table中读取时,它会使用这个列来实例化右边的class。这就是所谓的 single-table 继承 (STI) 或 table-per-hierarchy (TPH)。这种方法的主要缺点是所有 classes 的所有属性必须在同一个 table 上表示。例如,如果您要创建一个新的学生,则讲师的列仍会保留在记录中,只是这些值具有空值或默认值。这也意味着您不能在数据库级别对诸如 Instructor 之类的对象强制执行 属性,因为这会阻止保存无法提供这些值的 ApplicationUser 和 Student 实例。换句话说,派生的 classes 上的所有属性都必须可以为空。但是,对于使用视图模型的表单,您仍然可以始终强制执行类似 属性 的要求。
如果您真的想要单独的 table,您可以通过将继承策略更改为所谓的 table-per-type (TPT) 来实现该目标。这将做的是为 ApplicationUser 保留 table,但添加两个额外的 table,每个用于 Instructor 和 Student。但是,所有核心属性、外键等都将位于 ApplicationUser 的 table 上,因为这是定义它们的地方。用于 Instructor 和 Student 的 table 将仅包含在那些 class 上定义的属性(如果有)和用于 ApplicationUser 的 table 的外键。查询时,EF 将执行联接以从所有这些 table 中引入数据,并使用适当的数据实例化适当的 class。一些纯粹主义者更喜欢这种方法,因为它可以使数据库中的数据保持规范化。但是,由于连接,它在查询端必然更重。
最后一句警告,因为这会让人们经常处理身份继承问题。 UserManager class 是一个通用的 class (UserManager)。例如,AccountController 中的默认实例是 UserManager 的实例。因此,如果您使用该实例,则无论 Discriminator 列的值如何,从查询返回的所有用户都将是 ApplicationUser 实例。要获取 Instructor 实例,您需要实例化 UserManager 并将其用于您的 Instructor-related 查询。
核心 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 table。但是,我可以为每个 类 创建两个具有 identityUser 属性的 table 吗?
为了完成我的任务,我需要两个 table。我不知道如何实现我的想法
我认为您必须将 IdentityDbContext
与您的自定义模型一起注入。
您可以将模型映射到相应的 table。 example
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 创建一个 table 并向其添加鉴别器列。此列将具有三个可能值之一:"ApplicationUser"、"Instructor" 和 "Student"。当EF从这个table中读取时,它会使用这个列来实例化右边的class。这就是所谓的 single-table 继承 (STI) 或 table-per-hierarchy (TPH)。这种方法的主要缺点是所有 classes 的所有属性必须在同一个 table 上表示。例如,如果您要创建一个新的学生,则讲师的列仍会保留在记录中,只是这些值具有空值或默认值。这也意味着您不能在数据库级别对诸如 Instructor 之类的对象强制执行 属性,因为这会阻止保存无法提供这些值的 ApplicationUser 和 Student 实例。换句话说,派生的 classes 上的所有属性都必须可以为空。但是,对于使用视图模型的表单,您仍然可以始终强制执行类似 属性 的要求。
如果您真的想要单独的 table,您可以通过将继承策略更改为所谓的 table-per-type (TPT) 来实现该目标。这将做的是为 ApplicationUser 保留 table,但添加两个额外的 table,每个用于 Instructor 和 Student。但是,所有核心属性、外键等都将位于 ApplicationUser 的 table 上,因为这是定义它们的地方。用于 Instructor 和 Student 的 table 将仅包含在那些 class 上定义的属性(如果有)和用于 ApplicationUser 的 table 的外键。查询时,EF 将执行联接以从所有这些 table 中引入数据,并使用适当的数据实例化适当的 class。一些纯粹主义者更喜欢这种方法,因为它可以使数据库中的数据保持规范化。但是,由于连接,它在查询端必然更重。
最后一句警告,因为这会让人们经常处理身份继承问题。 UserManager class 是一个通用的 class (UserManager)。例如,AccountController 中的默认实例是 UserManager 的实例。因此,如果您使用该实例,则无论 Discriminator 列的值如何,从查询返回的所有用户都将是 ApplicationUser 实例。要获取 Instructor 实例,您需要实例化 UserManager 并将其用于您的 Instructor-related 查询。