我可以在ASP.NET MVC中创建多个身份表吗?

时间:2017-02-10 15:48:24

标签: asp.net-mvc-5 asp.net-identity

在我的项目中,Admin添加了教师,然后每位教师都会添加他的学生。添加后,他们会收到一封电子邮件,要求他们完成注册。

我的项目中有以下课程:

1学生班

Student: int id, int Registry number, int grade, string password, string email, string name

2-Instructor class:

Instructor: int id, string name , string email , string password

3-My database context:

 public class InstructorContext:DbContext
{
    public InstructorContext() : base("InstructorContext")
    {
    }

    public DbSet<Instructor> Instructors { get; set; }
    public DbSet<Student> Students { get; set; }}

当用户进入时,我必须确定他是管理员,讲师还是学生。我是否必须使用基于角色的身份验证?我已经有两个不同角色的单独课程。它们是否可以从IdentityUser继承?

1 个答案:

答案 0 :(得分:5)

不,您不能拥有多个具有Identity的用户表,至少不能技术上。身份的所有其他核心组件(角色,声明,登录等)都使用外键设置到一个用户表。

对于您的场景,您应该使用继承。例如:

public class ApplicationUser : IdentityUser

public class Instructor : ApplicationUser

public class Student : ApplicationUser

默认情况下,Entity Framework会为ApplicationUser创建一个表,并为其添加Discriminator列。此列将具有三个可能值之一:“ApplicationUser”,“Instructor”和“Student”。当EF从该表中读取时,它将使用此列来实例化正确的类。这就是所谓的单表继承(STI),或者称为每层次表(TPH)。这种方法的主要缺点是所有类的所有属性必须在同一个表上表示。例如,如果您要创建新的StudentInstructor的列仍将在记录中,只有这些值的空值或默认值。这也意味着您无法在数据库级别上强制要求Instructor之类的属性,因为这会阻止保存无法提供这些值的ApplicationUserStudent个实例。换句话说,派生类中的所有属性都必须是可空的。但是,您始终可以使用视图模型强制执行类似于表单所需的属性。

如果确实希望拥有单独的表,则可以通过将继承策略更改为所谓的table-per-type(TPT)来实现该目标。这样做的目的是保留ApplicationUser的表格,但添加两个额外的表格,分别用于InstructorStudent。但是,所有核心属性,外键等都将放在ApplicationUser的表中,因为那是定义它们的地方。 InstructorStudent的表将仅包含在这些类(如果有)上定义的属性以及ApplicationUser表的外键。查询时,EF将进行连接以从所有这些表中引入数据,并使用适当的数据实例化相应的类。像这样的一些纯粹主义者更好地保持数据在数据库中的标准化。但是,由于连接,它在查询方面必然更重。

最后一句警告,因为这会让人们不断地处理继承与身份。 UserManager类是泛型类(UserManager<TUser>)。例如,AccountController中的默认实例是UserManager<ApplicationUser>的实例。因此,如果您使用该实例,则无论ApplicationUser列的值如何,从查询返回的所有用户都将是Discriminator个实例。要获取Instructor个实例,您需要实例化UserManager<Instructor>并将其用于与Instructor相关的查询。

首次创建用户尤其如此。请考虑以下事项:

var user = new Instructor();
UserManager.Create(user);

您可能希望使用“Instructor”的鉴别器值保存用户,但实际上将使用“ApplicationUser”保存。这是因为,UserManagerUserManager<ApplicationUser>的一个实例,而您的Instructor正在升级。同样,只要你记得使用适当类型的UserManager<TUser>,你就可以了。