如何规范不同用户组具有不同类型配置文件的数据库?
Posted
技术标签:
【中文标题】如何规范不同用户组具有不同类型配置文件的数据库?【英文标题】:How to normalize a database where different user groups have different kinds of profiles? 【发布时间】:2011-03-03 13:41:57 【问题描述】:我的应用程序数据库有一个 Groups 表,它将用户划分为逻辑角色并定义访问级别(管理员、所有者、销售人员、客户服务等)
群组有很多用户。 Users 表包含登录详细信息,例如用户名和密码。
现在我希望将用户配置文件添加到我的数据库中。我遇到的麻烦(可能是由于我对适当的数据库规范化相对不熟悉)是不同的用户组具有不同类型的配置文件。因此,销售人员的个人资料将包括他的佣金百分比,而管理员或客户服务不需要此值。
那么,正确的方法是为每个组创建一个唯一的配置文件表吗? (例如 admin_profiles 或 salesperson_profiles)。或者是否有更好的方法可以将某些详细信息组合在通用配置文件中,而某些用户具有扩展信息。如果是这样,有什么很好的例子来说明如何使用给出的佣金示例来做到这一点?
【问题讨论】:
【参考方案1】:如果您的组从长远来看不会改变,我建议为每个组的每个配置文件保留单独的表 - admin_profile、salesperson_profile。以所有这些配置文件类型在用户对象本身中可用的方式设计您的对象模型。
编辑
如果您的对象模型是合理的,那么您可以执行以下操作。
使用来自 USer 和 Groups 表的外部引用创建一个表 USerProfiles。添加两个列,ProfileFieldName 和 ProfileFieldValue。还要添加一个主键字段。在运行时,继续为每对组和用户添加 ProfileFieldName 和值,只要适用。最重要的是,在对象模型的 User 对象中,提供指向 ProfileFieldName 的类型化属性。
我仍然建议您使用以前的方式,因为这样做会花费您更多的查询和更多的处理周期。在这种方法中,构建用户对象将花费相对更多的时间和处理。
【讨论】:
您提出了一个关于用户组的好问题。我想这些组将保持不变,但我将来可能需要添加新组。【参考方案2】:这取决于个人资料信息的不同程度。在我们的案例中,与其他用户相比,销售人员拥有我们存储的更多信息。我们需要了解他们所在的地区、销售队伍或他们所在的队伍、他们所代表的品牌等。
如果您只有一个或两个不同的数据,只需添加列并使其可为空。如果您有很多额外的数据,您将需要销售人员数据表,而不是其他组。这些很多是具有一对一关系或一对多关系的表,具体取决于数据的性质。
但将适用于所有人的一般个人资料信息保存在一处。最终,您可能拥有多个角色(销售人员和管理员)的用户,因此您希望基本用户信息只存储一次。
【讨论】:
【参考方案3】:最好的方法可能是有一个表admin_profiles
,一个表salesperson_profiles
,等等。每个表都应该有一个引用基本“用户”表的外键,并且适用于所有(或大多数)类型用户的任何属性都应该是“用户”表中的列。
我假设不同角色的列表将被修复,即系统用户不必添加新的、任意类型的角色。如果是这种情况,您可能会在 EAV 领域,我知道这不是很有趣。
【讨论】:
【参考方案4】:其他供应商已使用的另一个选项是只有 2 个表。一个列出了定义配置文件的属性,例如磁盘空间、返回的行数等。另一个列出了哪些组具有该选项。 Oracle 做了非常相似的事情。
这比其他方法更容易扩展,但限制了您如何将新的名称-值对添加到结构中。例如,如果名称-值对中有 3 个元素,您可能会遇到麻烦。但我认为这是更简单、更简洁、更具可扩展性和更简单的方法。
【讨论】:
【参考方案5】:最好的办法是使用 user_meta 表来存储用户的 id、元名称(佣金或您想要存储的其他值)和元值。
这样,您可以添加和删除字段,而无需更改数据库,也不必一直查看不同的表。
所以你可以拥有
user_id | meta_name | meta_value
10 | commission | 1.5%
50 | CS rating | 85%
其中用户 #10 是销售人员,用户 #50 是客户服务代表。
【讨论】:
然而,它是最灵活的,而且该项目听起来更像是一个内部 HR 应用程序,而不是从外部源源不断地访问的东西。最终,当事情开始发生变化并且管理层想要更改某些功能时,EAV 设计将节省大量浪费的时间。 我之前使用过“meta_key”“meta_value”结构。我认为 WordPress 在某些方面也使用了这种结构。 它适用于用户表和发布表,以及类似的一般任意选项。 假设我做了这样的事情,如果用户有一个包含静态信息(如姓名和电话号码)的个人资料,并且个人资料在键=>值对表中有许多“可选字段”怎么办? 将常用信息,如用户名、名字、姓氏、电子邮件、电话号码存储在自己的表中,其余的存储在元数据中。当您需要额外的内容时,您可以对数据库进行两次单独的访问。您也可以完成一次连接,但两次旅行是最简单的。将结果列表读入一个数组,然后从那里开始。在获取所有用户数据的函数之外,您的代码不需要知道两个表之间存在差异。【参考方案6】:在这种情况下,这些配置文件真正由实际标准定义,我可能会建议使用专用于每种类型的表。但是,为了全面披露,您可以使用 EAV 系统来存储这些信息。类似于:
User:
UserID
...
ProfileID
Profile:
ProfileID
Name
Criteria:
CriteriaID
Name
ProfileCriteria:
ProfileID
CriteriaID
UserCriteria:
UserID
CriteriaID
Profile
表定义配置文件的父表。对于您的每种个人资料类型,您将在其中有一行。
Criteria
定义了可以存在于配置文件中的基本条件,无论是哪个配置文件(例如,您可能在多个配置文件上具有相同的条件)。
CriteriaProfile
用于在 Profile
和 Criteria
之间创建 m:m 关系。您还可以在此处添加诸如为特定配置文件中的条件排序等内容。
UserCriteria
指向用户在给定条件下的特定值。这还允许您为用户切换配置文件,并通过删除那些不属于新配置文件的标准来维护任何常见的标准。
但是
EAV 结构需要大量维护。您现在必须自己管理结构化数据,而不是依赖 RDBMS 的工具来管理结构化数据(这是人们花很多钱才想出来的)。与非 EAV 系统相比,表格往往变得非常大,速度要快得多,因为您的行数是其数倍(因为您现在有一行用于正常结构中的每一列)。
EAV 功能强大且灵活,但并非始终是解决方案。如果您的个人资料需要动态,那么它们可能是一个合适的工具。
【讨论】:
我采用了与此答案类似的解决方案。我有组 hasMany Users 和 hasMany GroupProfileOptions。用户有一个用户配置文件。 UserProfile有很多UserProfileOptions,其中这些属于GroupProfileOptions。以上是关于如何规范不同用户组具有不同类型配置文件的数据库?的主要内容,如果未能解决你的问题,请参考以下文章
在jetstream更新表单中更新用户配置文件时,将用户的不同类型数据保存在不同的表中
如何正确设置具有三种不同用户类型和每种类型不同授权的 Rails 4 Devise 身份验证?