【问题标题】:ASP.NET Core 2.2 Entity Inheritance and db referenceASP.NET Core 2.2 实体继承和数据库引用
【发布时间】:2019-06-10 12:30:13
【问题描述】:
https://docs.microsoft.com/en-us/aspnet/core/security/authentication/customize-identity-model?view=aspnetcore-2.2 解释如何通过子类化扩展默认标识。我按照说明进行了代码设置,并且可以正常工作,但是现在我想进一步扩展它,因为根据用户角色,有不同的属性。例如。 ApplicationUser 可以有收藏夹,但扩展的 ApplicationUser 有 Elements。
我想创建更多 ApplicationUser 的子类。这是一个好主意吗?
模型是元素。 ApplicationUser 有一组元素,可以收藏它们。
ExtendedApplicationUser 继承自 ApplicationUser,可以添加 ApplicationUser 可以收藏的 Element 实例。
我该怎么办?
- 我是否为 ApplicationUser 和 ExtendedApplicationUser 创建角色并在 ApplicationUser 中声明这两个集合,没有子类。
- 还是我将 ApplicationUser 子类化,将每个集合放在每个类中?
我的第一个想法是继承 ApplicationUser,但我不确定使用角色是否是更好的方法。
最后一个问题,如何在 ApplicationUser 实体中声明集合?我使用 HashSet 还是 DbSet?
【问题讨论】:
标签:
c#
asp.net-mvc
asp.net-core
entity-framework-core
【解决方案1】:
是的,一般来说,继承是对此建模的正确方法。您只需要一个继承自IdentityUser 的类。这将是您的基础ApplicationUser。然后,其他类型的用户将继承自ApplicationUser。
也就是说,EF Core 对继承的处理还有很多不足之处。特别是它只支持TPH(table-per-hierarchy),也称为单表继承。换句话说,无论您做什么,您都只会拥有一个用户表,并且所有用户类型的所有道具都必须驻留在该表中。实际上,这仅意味着您的子类上不能有不可为空的属性,因为其他子类将无法为这些属性提供值,然后插入将失败。但是,这可以通过使用视图模型并将您的业务规则应用于需要的和不需要的业务规则来缓解。您不会在数据库级别获得验证,但通过表单等输入将始终得到验证。
以上内容值得一提,鉴于您无法使用更合适的数据库建模策略,例如按类型表 (TPT) 或按具体类型表 (TPC),因此使用继承是毫无意义的数据库视角。除非您需要在代码中强制规定只能针对特定用户类型修改某些属性或其他属性,否则您可以只使用单个用户类。拥有多种用户类型并非易事,因此除非您非常需要这样做,否则有理由让它保持简单。
特别是,如果您不小心,很容易弄乱用户的输入。单表继承通过添加一个包含正在保存的实际类型的鉴别器列来工作。换句话说,如果您保存ApplicationUser,则该值为“ApplicationUser”,或者如果您保存ExtendedApplicationUser,则该值为“ExtendedApplicationUser”。 EF 使用这个值来确定它应该实例化什么类型。棘手的地方是UserManager<TUser>。泛型类型参数,而不是传递给 CreateAsync 之类的方法的参数决定了将被保存的类型。例如,如果您新建一个ExtendedApplicationUser,但通过UserManager<ApplicationUser> 实例保存它,那么它将被向上转换为ApplicationUser 然后保存,导致“ApplicationUser”被写入鉴别器列。如果您需要使用ExtendedApplicationUser,那么您将需要一个UserManager<ExtendedApplicationUser> 实例,并且您最终可能会拥有多个这样的用户管理器,每个管理器都用于处理特定类型的用户。因此,您需要小心为正确的场景使用正确的用户管理器。
对于你最后一个问题,答案是否定的。集合属性应为ICollection<TEntity> 或List<TEntity>。 HashSet 可用于在写入属性时满足 ICollection<TEntity>,但不要这样键入。 DbSet 仅用于上下文。