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