考虑以下:
entity User
{
autoincrement uid;
string(20) name;
int privilegeLevel;
}
entity DirectLoginUser
{
inherits User;
string(20) username;
string(16) passwordHash;
}
entity OpenIdUser
{
inherits User;
//Whatever attributes OpenID needs... I don't know; this is hypothetical
}
Run Code Online (Sandbox Code Playgroud)
不同类型的用户(直接登录用户和OpenID用户)表现出IS-A关系;也就是说,这两种类型的用户都是用户。现在,有几种方法可以在 RDBMS 中表示:
方式一
CREATE TABLE Users
(
uid INTEGER AUTO_INCREMENT NOT NULL,
name VARCHAR(20) NOT NULL,
privlegeLevel INTEGER NOT NULL,
type ENUM("DirectLogin", "OpenID") NOT NULL,
username VARCHAR(20) NULL,
passwordHash VARCHAR(20) NULL,
//OpenID Attributes
PRIMARY_KEY(uid)
)
Run Code Online (Sandbox Code Playgroud)
方式二
CREATE TABLE Users
(
uid INTEGER AUTO_INCREMENT NOT NULL,
name VARCHAR(20) NOT NULL,
privilegeLevel INTEGER NOT NULL,
type ENUM("DirectLogin", "OpenID") NOT NULL,
PRIMARY_KEY(uid)
)
CREATE TABLE DirectLogins
(
uid INTEGER NOT_NULL,
username VARCHAR(20) NOT NULL,
passwordHash VARCHAR(20) NOT NULL,
PRIMARY_KEY(uid),
FORIGEN_KEY (uid) REFERENCES Users.uid
)
CREATE TABLE OpenIDLogins
(
uid INTEGER NOT_NULL,
// ...
PRIMARY_KEY(uid),
FORIGEN_KEY (uid) REFERENCES Users.uid
)
Run Code Online (Sandbox Code Playgroud)
方式三
CREATE TABLE DirectLoginUsers
(
uid INTEGER AUTO_INCREMENT NOT NULL,
name VARCHAR(20) NOT NULL,
privlegeLevel INTEGER NOT NULL,
username VARCHAR(20) NOT NULL,
passwordHash VARCHAR(20) NOT NULL,
PRIMARY_KEY(uid)
)
CREATE TABLE OpenIDUsers
(
uid INTEGER AUTO_INCREMENT NOT NULL,
name VARCHAR(20) NOT NULL,
privlegeLevel INTEGER NOT NULL,
//OpenID Attributes
PRIMARY_KEY(uid)
)
Run Code Online (Sandbox Code Playgroud)
我几乎可以肯定第三种方式是错误的方式,因为不可能对数据库中其他地方的用户进行简单的连接。
我的真实世界示例不是具有不同登录示例的用户;我对如何在一般情况下对这种关系建模很感兴趣。
Nic*_*mas 17
方法二是正确的方法。
您的基类获取一个表,然后子类获取他们自己的表,其中仅包含它们引入的附加字段,以及对基表的外键引用。
正如乔尔在他对这个答案的评论中所建议的那样,您可以通过向每个子类型表添加一个类型列来保证用户将拥有直接登录或 OpenID 登录,但不能同时拥有(也可能两者都没有)到根表。每个子类型表中的类型列被限制为具有表示该表类型的单个值。因为这一列是根表的外键,所以一次只能有一个子类型行可以链接到同一个根行。
例如,MySQL DDL 将类似于:
CREATE TABLE Users
(
uid INTEGER AUTO_INCREMENT NOT NULL
, type ENUM("DirectLogin", "OpenID") NOT NULL
// ...
, PRIMARY_KEY(uid)
);
CREATE TABLE DirectLogins
(
uid INTEGER NOT_NULL
, type ENUM("DirectLogin") NOT NULL
// ...
, PRIMARY_KEY(uid)
, FORIGEN_KEY (uid, type) REFERENCES Users (uid, type)
);
CREATE TABLE OpenIDLogins
(
uid INTEGER NOT_NULL
, type ENUM("OpenID") NOT NULL
// ...
PRIMARY_KEY(uid),
FORIGEN_KEY (uid, type) REFERENCES Users (uid, type)
);
Run Code Online (Sandbox Code Playgroud)
(在其他平台上,您将使用CHECK约束而不是ENUM.) MySQL支持复合外键,因此这应该适合您。
第一种方法是有效的,尽管您在那些NULL-able 列中浪费了空间,因为它们的使用取决于用户的类型。优点是,如果您选择扩展要存储的用户类型类型,并且这些类型不需要额外的列,您只需扩展您的域ENUM并使用相同的表即可。
方式三强制任何引用用户的查询都检查两个表。这也可以防止您通过外键引用单个用户表。
| 归档时间: |
|
| 查看次数: |
33525 次 |
| 最近记录: |