我可以在 asp.net MVC-5 项目中的我的 aspnet 数据库中添加新的自定义表吗

Posted

技术标签:

【中文标题】我可以在 asp.net MVC-5 项目中的我的 aspnet 数据库中添加新的自定义表吗【英文标题】:Can i add new custom tables inside my aspnet database inside asp.net MVC-5 project 【发布时间】:2017-10-13 16:44:46 【问题描述】:

我有以下几点:-

    Visual Studio 2013。 我创建了一个新的 asp.net MVC-5 Web 项目。 该项目正在使用 asp.net identity 2.2。 对于身份验证方法,我选择了“个人用户帐户” 此进程创建了一个名为aspnet-OurProjectNanme-number 的新数据库 在自动生成的数据库中,我有一个名为AspNetUSers 的表,用于存储用户信息。

现在我正在构建一个 ERP 系统。在 ERP 系统中,我想添加以下内容:-

    一个名为“资产”的表,用于存储资产信息。 “资产”表将有 2 个名为“CreatedBy”+“ModifiedBy”的列,其中应存储创建和修改资产项的用户 ID。

现在我不确定我需要如何实现这一目标?因为我需要在我的自定义表“资产”和自动创建的“AspNetUsers”表之间添加一个外键。所以我可以在自动生成的数据库中添加我的自定义表“资产”,并构建Asset.CreatedByAspNetUsers.Id 之间的外键 ??

如果答案是,那么如果我们想升级我们的 aspnet 身份版本,这种关系会在未来中断吗?因为升级身份可能会导致创建新表或重命名现有表等。这可能会破坏 Asset 表和 AspNetUsers 表之间的关系?

如果答案是否定的(我不应该在自动生成的数据库中添加自定义表)那么我如何构建外键?在这种情况下我需要在哪里添加资产表??

【问题讨论】:

【参考方案1】:

您想要做的最常见的方法是将您的附加模型作为 DbSet 添加到您的 ApplicationDbContext 中。

public class Asset

      public string CreatedBy  get; set; 

      public string UserId  get; set; 

      public ApplicationUser User  get; set; 


public class ApplicationUser : IdentityUser

     public IList<Asset> Assets  get; set; 


public class ApplicationDbCotext : IdentityDbContext<ApplicationUser>

     public DbSet<Asset> Assets  get; set; 

正如我所提到的,这是最常见的方法,因为更新身份包应该不会影响您的架构。也就是说,您应该始终在投入生产之前测试更新。

更新: 请注意,当您使用一对多关系时,您将在我们的资产模型中看到 User Id 外键以及 User 对象的属性。由于这种关系,我们可以在我们的用户中创建一个List&lt;Asset&gt; 来完成一对多关系。这将允许我们直接查询属于用户的资产。

对于 Code First 与 Database First 的区别实际上归结为您如何定义实体框架和数据库之间的映射。

正如我在下面提到的,如果您将身份上下文与业务上下文分开,或者您应该将它们分开到单独的数据库中,没有一种适合所有的答案。现实情况是,只有您可以根据自己的需要回答这个问题。将所有数据放在一个数据库中更为常见。也就是说,对于将用户的识别信息(例如他们的姓名、电子邮件和密码哈希)与他们的地址或支付信息等信息分开的安全性,有一些话要说。权衡的是,您会发现自己试图维护应该绑定在一起但只是松散相关的对象,因为它们位于不同的数据库中。此外,您还需要确保您使用不同的用户/密码来连接到不同的数据库,并且最好将数据库放在不同的服务器上,因为如果服务器受到威胁,您就白费了整个练习。为获得理论上的安全性而进行的权衡最终变得如此不切实际,因为您始终需要做另一件事,以至于您最终会在一个数据库中看到所有内容,您可以集中精力进行所有强化工作。

当您File -&gt; New 具有个人身份验证的项目时,通常应该为您创建 ApplicationDbContext 和 ApplicationUser 对象。您可以根据需要向用户添加任意​​数量的属性和关系。

【讨论】:

现在明白你的意思是什么......因为我总是在 DB-First 方法上工作。所以你的意思是我可以添加我的自定义表,例如内置数据库中的资产,它会自动为我创建aspnet-OurProjectNanme-number,然后我可以创建一个新的.edmx(上下文),它只包含我的自定义表?所以主要是所有内置的表+自定义的表都在同一个数据库中,但是我将有 2 个上下文类,一个包含身份验证表,而另一个包含我的自定义表? 第二个问题你能对你提供的课程提供更多建议吗?现在您提到了以下课程public class User : IdentityUser public IList&lt;Asset&gt; Assets get; set; ,那么它的目的到底是什么?并且数据库级别内的用户和身份用户之间是否存在任何关系?外键或类似的东西?我的意思是当您定义public class User : IdentityUser 时,这将如何在数据库中进行翻译?我知道将创建一个新的用户表,但是用户和身份用户表之间会有任何 FK 吗?在数据库级别? 第三个问题.. 如另一个答案所述。在IdentityUser 等内置身份验证表和我的应用程序表之间没有直接关系是否更安全可靠?因为假设我在视图上显示资产信息,那么我将有让用户暴露身份验证表的风险,因为表之间存在直接关系? ..另一个答案建议有一个重复 IdentityUser 信息的 People 表,在这个 People 表中我可以添加我的所有自定义属性并与我的应用程序表(例如 Asset 表)建立关系? ?所以你能就我上面的3个问题给点建议吗? 通常当您执行File -&gt; New 时,您会得到一个类ApplicationDbContextApplicationUser。我将 ApplicationUser 缩短为 User。我知道有些人可能会争论他们的观点并说他们的方式是正确的方式。确实有不止一种方法可以做到这一点,这完全取决于您的要求。如果您要求您的用户数据库与应用程序的数据库完全不同,那么您可能需要创建一个映射对象。在我的经验中更常见的是,这种关系是直接在包括用户在内的模型之间定义的。【参考方案2】:

-- 更新--

答案越来越多,discussion 也是如此。我想我已经展示了各种各样的变化,这可能无助于使其易于理解。所以这里是一个总结。如需解释,请阅读完整答案和讨论。

开箱即用,您有两个上下文,身份和业务。这些是分离的,因此您可以更改安全性而不会干扰您的业务。这样,升级安全性不会破坏您的应用程序或其他模型。由于上下文是独立的,因此对其中任何一个的更改都不会影响另一个。

附带说明:您不打算直接访问 AspNet 身份表。实现 UserManager 并使用管理器的可用方法来执行操作。

现在谈到逻辑,信息应该存储在哪里?作为一个简单的规则,只要问自己一个问题:它是安全的一部分还是业务的一部分?

在这两种情况下,您都有用户。根据您的要求,这是一个合乎逻辑的 1:1 关系。但它们实际上是分开的。您可以在不提供登录名的情况下创建人员或删除登录名而不删除用户(人员),例如由于历史原因。

您只想找到当前用户的所有信息。因此,您只需要 People.Id。

无需更改 IdentityUser,您只需覆盖 AspNetUser.Id 即可创建 1:1 关系。

var appUser = new IdentityUser

    UserName = model.Email,
    Email = model.Email,
    Id = Convert.ToString(People.Id)
;
var identityResult = await userManager.CreateAsync(appUser, model.Password);

您的业务不需要身份上下文。您只需要 People.Id。身份上下文仅在颁发令牌和创建/修改用户时使用。

要获取 id,请使用以下内容:

 var peopleId = int.Parse(Request.User.Identity.GetUserId());

现在您可以使用 ID 查询您的业务模型。

注册时,使用您要存储的人员信息扩展 View 和 ViewModel。这将允许您同时添加 People 和 AspNetUser。虽然这不是一笔交易。但我认为,如果您先执行检查,创建任何一个都不太可能失败。

您可以在创建用户之前验证用户名和密码(使用 UserManager 中的方法)并检查视图模型的 ModelState。使用属性强制填写必填字段。

-- 原始答案--

为了不重复我自己,请阅读我的回答here。

简而言之,将身份和业务分开。 以防万一身份逻辑从同一个数据库中删除,例如在实现 IdentityServer 时。

您在 AspNetUser 中似乎有业务信息。如果是这样,请创建一个 Person 表并将信息移动到该表中。与模型中的该表相关。在 Person 表中,您可以添加对 AspNetUser 的引用。

-- 更新--

我认为您理解正确,但我将在此答案中添加详细信息。

在大多数情况下,所有表都定义在一个数据库中。但这并不意味着它们都是同一模型的一部分。可以有多个上下文。在这种情况下,一个用于身份,一个(或多个)用于业务。

现在为什么要把这两者分开? Business 模型和 Identity 模型之间最重要的区别是不能直接调用 Identity 表。我们使用 Owin 上下文来调用 UserManager / RoleManager。

这就是为什么我们不能将这些表添加到业务模型中。可以以不安全的方式更改事物。此外,我们不希望企业对授权有任何了解。只要用户被识别和授权,如何完成都无关紧要。

您还可能希望实现 OpenId 和基于声明的授权。在这种情况下,数据库中不必提供信息。

这个想法是创建身份表 AspNetUsers 和业务表 People 的 1:1 关系。可能会有一些冗余,例如电子邮件或(用户)名称。但这不是问题。人员表应包含您要在业务模型中使用的所有信息。并且业务表应该只与人相关,而不是与 AspNetUsers 相关。

现在关于 AspNetUsers 和 People 之间的链接。有四种选择:

    设置 People.Id = AspNetUser.Id。请注意,AspNetUser.Id 不必是 GUID。您可以添加自己的值作为键。

    设置 AspNetUser.Id = People.Id。

    将 AspNetUserId 列添加到 People。不需要对身份进行修改。您也可以将人员添加到身份模型中,但我认为您不能在一次事务中创建两条记录。您可以使用 User.Identity.GetId() 来获取 AspNetUser.Id。但是,您可能会问自己,企业是否应该了解这些信息。

    将列 PeopleId 添加到 AspNetUsers。您需要扩展 IdentityUser 以添加 PeopleId。一个优点是您不需要 AspNetUser Id,但您可以使用 People 的实际 Id。使用 OpenId 或声明时,您可以从声明中获取 People.Id,而不必将 AspNetUser.Id 添加到业务中。或者,您可以将人员添加到模型并作为扩展 IdentityUser 的导航属性。创建用户时,您可以在一个事务中完成此操作。

如果您在单独的上下文中创建用户,则需要自己处理回滚。但是在向 People 添加记录之前,您已经可以测试是否可以添加 AspNetUser:具有有效的名称/电子邮件和密码。

由于您的业务模型与 People 表相关,因此您可以查询所有资产并与 People 表连接以获取更多信息。或者您可以获取当前用户的所有资产。

是的,有两种情况。身份模型,其中包含 AspNet... 表 + 可选的 People。以及包含所有 ERP 表 + 资产 + 人员的业务模型。

您可以考虑将代码优先用于身份框架 2,将数据库优先用于业务模型。

我希望这会有所帮助。如果没有,让我们继续聊天。

-- 更新--

答案集中在域的分离上:身份和业务。这就是为什么我没有讨论关于 AspNetUsers 表的一种可能的替代方案。

这两个模型是数据库的表示,这意味着数据库不必完全匹配。您可以随意映射表和字段,只要它们不破坏数据库逻辑即可。

由于 AspNetusers 和 People 具有 1:1 的关系,并且两个表都存在于同一个数据库中,您不妨将两者合并到 AspNetUsers 表中。您还可以向 AspNetUsers 表添加关系,但您可能希望添加额外的 Id (int) 列而不是使用当前的 Id(字符串)。

这并不意味着可以丢弃 People 类,只是我们必须更改表映射:AspNetUsers。

例子:

[Table("AspNetUsers")]
public class People

    [Required]
    [StringLength(128)]
    public string Id  get; set; 

    public string FirstName  get; set; 

    public string LastName  get; set; 

如您所见,敏感字段未映射。然而,我们需要 Id 字段。您现在可以读取和更新映射的字段。

您不必扩展 IdentityUser。您可以添加一个 AspNetUser,然后在其他上下文中使用 People 更新字段。但是,如果您想在单个事务中添加用户,扩展 IdentityUser 可能会更容易(确保您将在 People 和 ApplicationUser 中定义新字段):

public class ApplicationUser : IdentityUser

    public string FirstName  get; set; 

    public string LastName  get; set; 

有多种优势:

    只有一个交易可以添加用户。 您不能公开敏感字段,因为它们未映射到人员中。 您无法将人员添加到数据库中,因为某些必填字段未映射到人员中。

请注意,这可能不适用于所有类型的模型(代码优先/数据库优先 + 迁移)。

【讨论】:

所以你的意思是我需要创建一个名为 Person 的新表。所以当一个新用户注册到我的应用程序时,用户将在 AspNetUsers 和 Person 表内有一条记录。这是正确的吗?所以我需要修改注册业务逻辑以在人员表中创建新记录?这是正确的吗?第二个问题。我需要在哪里添加 Person 表?在为我创建的内置数据库“aspnet-OurProjectNanme-number”中?或者我需要创建一个新数据库并在其中添加 Person 表? 是的,您需要维护 AspNetUsers 和 Persons。所以实际上存在 1:1 的关系。 Person 表应该是定义 Asset 的同一模型的一部分,因为您想在两个表之间创建关系。 所以让我总结一下答案.. 现在我需要创建一个新数据库,比如说“MyCustomDB”,向其中添加资产和人员表......现在当用户在应用程序中注册时,我需要在 Person 表中创建一条记录??并且 person 表与 AspNetUsers 没有任何关系???如果答案是肯定的,那么我能看到的唯一问题是我将有两个 DBContext,所以假设一个用户在我的应用程序中正确注册,其中创建了 AspNetUsers 中的新用户, 现在当我尝试在 Person 表中创建新记录时出现问题(例如数据库关闭)..那么在这种情况下我会得到不一致的结果,这是正确的吗?因为我不能在 2 个独立的数据库之间进行完全原子事务?这是正确的吗?还是我直面这种痛苦? 不需要新建数据库,所有表都可以存放在同一个数据库中。但两者有不同的背景。 IdentityContext 和 BusinessContext。是的,如果出现问题,您需要自己回滚。但是只要所有表都在同一个数据库中,您就可以将 Persons 添加到 IdentityModel 并使用 Person 扩展 IdentityUser(在模型中创建关系,而不是在数据库中),从而使其成为一个事务。

以上是关于我可以在 asp.net MVC-5 项目中的我的 aspnet 数据库中添加新的自定义表吗的主要内容,如果未能解决你的问题,请参考以下文章

Angular 路由模板 url 是不是支持 ASP.Net MVC 5 项目中的 *.cshtml 文件?

VS 2015 ASP.NET 4 MVC 5 中的打字稿 - 设置和选择的工作组合是啥?

ASP.NET MVC 5 - 身份。如何获取当前的ApplicationUser

控制器中的 Asp.Net MVC 5 ModelState 具有索引、添加、编辑

Azure 中的捆绑不适用于 bootstrap 和 jquery、ASP.NET MVC 5

asp net mvc 5中的授权帮助