我正在开发一个MVC项目,该项目需要使用Identity创建的身份验证和授权,我的项目数据库还包括应该使用该系统的主要实体,处理这种情况的最佳实践是什么。
答案 0 :(得分:1)
您当然应该自定义Identity实体,因为这是创建Identity的全部原因:允许更大的可扩展性。要拥有不同类型的"用户",您应该继承ApplicationUser
;重要的是,{em>不直接来自IdentityUser
。这将确保核心身份关系(角色,声明,登录等)都与单个用户"表,然后您可以扩展该表或创建其他表来保存其他用户数据。
public class ApplicationUser : IdentityUser
public class Student : ApplicationUser
public class Instructor : ApplicationUser
默认情况下,此继承将由TPH(每个层次表)实现,也称为STI(单表继承)。这意味着所有派生类的所有属性都将由单个数据库表上的列表示。还会添加Discriminator
列,其中包含已保存的实际类的名称,即" ApplicationUser","学生"或"讲师& #34 ;.当您从查询中构建对象图时,EF将使用此列来实例化正确的" user"类型。
这种方法有利有弊。由于所有内容都存在于单个表中,因此查询简单快捷。但是,此方法必须使每个派生类的所有属性必须在数据库级别上为可空。显而易见的原因是,如果Instructor
有必填列,则无法保存Student
,因为Student
不具备满足该要求的属性。您仍然可以使用视图模型强制在视图级别需要这些属性。但是,数据库中的实际列必须是可为空的。
另一种方法是使用名为TPT(Table Per Type)的内容。在此继承策略中,将为具有所有公共属性的基类(ApplicationUser
)创建一个表。然后,将为每个谨慎的派生类创建一个表,只包含该类中存在的属性。外键将添加到基类的表中,然后EF将用于将该表中的公共数据连接到派生类的特定数据。表。这种方法允许您在数据库级别强制执行NOT NULL,但它当然需要连接来引入所有数据,这会降低查询速度。
要实现TPT,您只需要将[Table]
注释添加到派生类中:
[Table("Students")]
public class Student : ApplicationUser
[Table("Instructors")]
public class Instructor : ApplicationUser
最后要注意的是,您需要如何使用UserManager
。如果你搭建了AccountController
,你会注意到它设置了一个UserManager
控制器属性,然后用它来创建用户,查找用户,更改密码等。这实际上是一个实例UserManager<ApplicationUser>
的{{1}},因为它是一种通用类型。如果您需要专门使用Student
或Instructor
,则需要分别实例化UserManager<Student>
和UserManager<Instructor>
。您无法使用UserManager<ApplicationUser>
的实例,因为它会将您的派生类型转发为ApplicationUser
。例如:
var student = new Student { ... };
await UserManager.CreateAsync(student);
实际上会导致ApplicationUser
保存到数据库中。特定于学生的数据将被丢弃,Discriminator
列的值将为&#34; ApplicationUser&#34;。