说服怀疑论者!为什么我的数据库中需要“角色”表?

时间:2011-06-06 19:32:37

标签: database-design user-roles

在设计用于存储简单用户/角色信息的数据库表时,任何人都可以告诉我为什么将角色信息直接存储在User表中是个坏主意(例如,Roles列中的逗号分隔)。

思想:

  1. 数据库不需要知道角色,即UI的域
  2. 更快地访问特定用户的角色
  3. 当然,如果将来某个时候我想要访问特定角色的所有用户,查询可能会
  4. 有点慢,但谁在乎这一点?

    这有什么意义吗?我是不是摇摇欲坠了?不会创建角色和UserRole表是否过度,并添加不必要的SQL和代码开销?

    更新:

    为了进一步说明我的观点......在代码中,我想知道用户“Steve”是否担任“管理员”角色。

    选项1:在UserRole表中查询用户“Steve”的角色列表。循环遍历该列表,查看RoleName是否与“Administrator”匹配。

    选项2:在用户角色属性中拆分csv并查看结果列表是否包含“管理员”

    更新II:

    我同意我的建议违反了各种“最佳实践”类型思维,特别是在数据库设计方面。但是,我没有看到“最佳实践”在这种情况下如何有意义。我喜欢偶尔摇滚最佳实践船......我喜欢以一种看起来很聪明的方式编码,这意味着有时我需要了解更多才能知道我什么时候不聪明:)

5 个答案:

答案 0 :(得分:2)

因为它违反了第3范式。您希望将所有实体分隔为不同的对象,这意味着您需要一个单独的表,以及一个关系表。

违反数据

如果将所有这些保留在一个表中,则会在用户表中放置太多与用户无关的信息。用户的表应该包含仅与该用户相关的字段,例如其名称,用户帐户等。但在这种情况下,您决定引入一些角色信息。这是没有意义的,因为您添加的属性并不一定与用户有任何关系。

结果是您开始添加与用户无关的字段,并且您最终会收到大量不相关的信息。对此的解决方案是有一个像这样的用户表:

User table
UserID
User
...

Role table
RoleID
Role
....

User Role Table (the relationship)
UserRoles
UserID
RoleID
...

更新/插入数据

如果将角色信息存储在用户表中,则必须处理的下一个问题是如何执行有效更新,插入。这使得它变得更加困难。编辑记录时,必须确保从CSV编辑正确的值。

找到合适的角色

这是最困难的问题,如何找到给用户的角色。您可能会在C#或SQL Server中提出这种出色的解析技术,但它的工作效果很好。但它变得非常慢且难以阅读。您开始处理SubString()Left()Right()Len()以及一大堆其他功能,只是为了解析用户的角色。

解决方案

您可能认为现在将它全部放在一个表中会更容易。它可能需要很少的时间。但是你必须开发应用程序并考虑到未来。如果您遵循3nf的规则并创建一个漂亮的关系结构,UI将更加简单。 UI管理界面不仅看起来不错,而且获取特定用户ID的角色也是如此微不足道,而不是解析或搜索......

答案 1 :(得分:1)

我认为这不是一个好计划。假设您手动更新某人的角色并且您输入的角色名称略有错误?如果您有一个单独的表,数据库约束会警告您。假设您决定更改角色的名称?如果你有一个单独的表,你只需要在一个地方更改它。

数据库规范化有充分理由;这不仅仅是挑剔。您不会在多个地方重复代码库中的密钥代码;数据库非规范化是等价的。

已编辑添加: 您指出应用程序最终将根据数据库返回的值做出决策;例如如果用户具有名为“Admin”的角色,则授予某些选项。这是事实,它是另一个独立的地方,例如,角色名称的一致性可能会出错。我不认为对数据库进行非规范化会降低这种可能性。

帮助解决这个问题的一个好方法(以及一般实施授权的好方法)是在代码中有一个位置,其中角色被转换为某些一般能力(例如,管理员可以读写所有实体,客人可以读取某些实体,不能写任何东西等)。然后,在您需要建立访问权限的许多地方,您需要检查一项能力,而不是检查角色。

也就是说,在视图中,如果您决定是否在项目描述中显示“编辑”按钮,则不要通过执行if role=='ADMIN' or role=='EDITOR'进行检查,您可以通过执行{ {1}}。在其他地方,您已经确定管理员和编辑者能够编辑项目。例如,请参阅Rails授权系统CanCan使用的方法。

使用这种方法,只有一个地方可以引用角色的名称(例如,在CanCan中,你有一个名为“能力”的类,它根据角色定义了谁可以做什么的所有规则。否则,您可以参考用户具有哪些能力来确定他们可以做什么或看到什么。

答案 2 :(得分:0)

  1. 您需要额外的逻辑来解析代码端的CSV。
  2. 大多数ORM不支持CSV。
  3. 如果你有一个很长的角色名称(例如UserWhoHaveAccessToXObjButNotYObjAndAtTheSameTimeCanDoZ),那么你就是在为所有用户浪费空间重复它。
  4. 此外,您的第一个假设不适用于所有情况。如果我的数据库需要了解角色怎么办?

答案 3 :(得分:0)

这取决于您是希望数据库管理系统管理数据还是希望应用程序管理数据。在大多数情况下,DBMS做得更好,因为它就是它的基础。

答案 4 :(得分:-1)

你说

  

那么为什么不定义角色呢?   在应用程序中,只在   应用

只有当你真实地说:“我百分之百地确保每个程序员和每个数据库管理员都能完全手动保存数据完整性时,无论应用程序接触到哪个数据库,无论用何种语言编写,我都能可靠地做到这一点。无论程序员多么有经验或缺乏经验,无论数据库变得多么复杂,从现在开始直到生命结束。“

如果您达到职业生涯中管理编程项目的重点,您的部分工作就是将编码职责分配给最适合执行编程的人员。在架构层面,有人还将程序职责(如数据完整性)分配给最适合执行它们的模块或子系统。通过将该责任分配给dbms,数据完整性只能保证。将它分配给系统的任何其他部分,无论是代码还是人,都只是希望的表达,希望不能很好地扩展。