问题描述
我正在研究一个需要通过身份验证创建的身份验证和授权的MVC项目,而且我的项目数据库还包括应使用该系统的主要实体,这是应对这种情况的最佳实践.
I'm working on an MVC project that required an authentication and authorization which will be created using Identity, also my project database includes main entities that should use the system, what is the best practice to deal with that situation.
- 我是否应该根据自己的需求自定义身份ApplicationUser.
- 创建我自己的表(模型)并将它们与身份表集成在一起,我不知道该怎么做.或任何其他解决方案.
- Should I customize the identity ApplicationUser to my requirements.
- Create my own tables (models) and integrate them with identity tables and I don't know how to do that.or any other solutions.
推荐答案
您当然应该自定义Identity实体,因为这是创建Identity的全部原因:允许更大的可扩展性.要具有不同类型的用户",您应该继承ApplicationUser
;重要的是,直接来自IdentityUser
的不是.这样可以确保核心身份关系(角色,声明,登录名等)都绑定到一个用户"表,而后您可以扩展该表或创建其他表来保存其他用户数据.
You should of course customize the Identity entities, as that is the whole reason for the creation of Identity: to allow greater extensibility. To have different types of "users", you should inherit from ApplicationUser
; importantly, not from IdentityUser
directly. This will assure that the core Identity relationships (roles, claims, logins, etc.) are all tied to a single "user" table, while you can then either extend that table or create other tables to hold additional user data.
public class ApplicationUser : IdentityUser
public class Student : ApplicationUser
public class Instructor : ApplicationUser
默认情况下,此继承将由TPH(每个层次的表)(也称为STI(单表继承))实现.这意味着所有派生类的所有属性将由单个数据库表上的列表示.也将添加一个Discriminator
列,其中将保存已保存的实际类的名称,即"ApplicationUser","Student"或"Instructor".在通过查询构建对象图时,EF将使用此列来实例化正确的用户"类型.
By default, this inheritance will be implemented by TPH (Table Per Hierarchy), also known as STI (Single Table Inheritance). What that means is that all properties from all derived classes will be represented by columns on a single database table. A Discriminator
column will also be added, which will hold the name of the actual class that was saved, i.e. "ApplicationUser", "Student", or "Instructor". EF will use this column when building object graphs from your queries to instantiate the right "user" type.
这种方法有利有弊.由于所有内容都存在于单个表中,因此查询既简单又快速.但是,这种方法必须使每个派生类的所有属性在数据库级别必须为空 .显而易见的原因是因为如果Instructor
具有必填列,则您将无法保存Student
,因为Student
将不具有满足该要求的属性.您仍然可以使用视图模型在视图级别强制要求属性.但是,数据库中的实际列必须可以为空.
There's pros and cons with this approach. Since everything exists in a single table, queries are simple and quick. However, this approach necessitates that all properties on each derived class must be nullable at the database level. The obvious reason why is because if Instructor
has a required column, you would not be able to save Student
, since Student
would not have the property to fulfill that requirement. You can still enforce that properties be required at the view level, using view models. The actual column in the database must be nullable, though.
另一种方法是使用所谓的TPT(每种类型的表).在这种继承策略中,将为具有所有公共属性的基类(ApplicationUser
)创建一个表.然后,将为每个离散派生类创建一个表,仅包含该类上存在的属性.外键将添加到基类的表中,然后EF将使用该外键将表中的公共数据连接到派生类的表中的特定数据.这种方法允许您在数据库级别强制执行NOT NULL,但是它当然需要联接以引入所有数据,这会降低查询速度.
An alternative approach is to use what's called TPT (Table Per Type). In this inheritance strategy, a table will be created for the base class (ApplicationUser
) with all common properties. Then, a table will be created for each discreet derived class, with just the properties that exist on that class. A foreign key will be added to the table for the base class, which EF will then use to join the common data from that table to the specific data on your derived class' table. This approach allows you to enforce NOT NULL at the database level, but it of course requires a join to bring in all the data, which can slow down your queries.
要实现TPT,只需将[Table]
批注添加到派生类:
To implement TPT, you need simply to add the [Table]
annotation to your derived class:
[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
.例如:
One final thing of note is how you'll need to utilize UserManager
. If you scaffolded your AccountController
, you'll notice that it sets up a UserManager
controller property, which is then utilized to create users, lookup users, change passwords, etc. This is actually an instance of UserManager<ApplicationUser>
, as it's a generic type. If you need to specifically work with Student
or Instructor
, you'll need to instantiate UserManager<Student>
and UserManager<Instructor>
, respectively. You can't use an instance of UserManager<ApplicationUser>
as it will upcast your derived type to ApplicationUser
. For example:
var student = new Student { ... };
await UserManager.CreateAsync(student);
实际上将导致ApplicationUser
被保存到数据库中.特定于学生的数据将被丢弃,并且Discriminator
列的值为"ApplicationUser".
Would actually result in ApplicationUser
being saved to the database. The student-specific data will be discarded and the Discriminator
column's value would be "ApplicationUser".
这篇关于具有mvc5身份的自定义数据库的自定义和集成的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!