数据库设计 – 如何将IS-A关系映射到数据库?

前端之家收集整理的这篇文章主要介绍了数据库设计 – 如何将IS-A关系映射到数据库?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
考虑以下:
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
}

不同类型的用户(直接登录用户和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)
)

方式二

CREATE TABLE Users
(
    uid INTEGER AUTO_INCREMENT NOT NULL,privilegeLevel INTEGER 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
)

方式三

CREATE TABLE DirectLoginUsers
(
    uid INTEGER AUTO_INCREMENT NOT NULL,PRIMARY_KEY(uid)
)

CREATE TABLE OpenIDUsers
(
    uid INTEGER AUTO_INCREMENT NOT NULL,//OpenID Attributes
    PRIMARY_KEY(uid)
)

我几乎可以肯定第三种方式是错误的方式,因为不可能对数据库中其他地方的用户进行简单的连接.

我的真实世界示例不是具有不同登录示例的用户;我对如何在一般情况下模拟这种关系感兴趣.

解决方法

方式二是正确的方法.

您的基类获取一个表,然后子类只使用它们引入的其他字段获得自己的表,以及对基表的外键引用.

正如Joel在对此答案的评论中所建议的那样,您可以保证用户将具有直接登录或OpenID登录,但不能同时(也可能两者都没有)通过向每个子类型表添加类型列来锁定到根表.每个子类型表中的type列被限制为具有表示该表类型的单个值.由于此列是外键到根表,因此一次只能有一个子类型行链接到同一根行.

例如,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
    // ...,FORIGEN_KEY (uid,type) REFERENCES Users (uid,type)
);

CREATE TABLE OpenIDLogins
(
      uid               INTEGER NOT_NULL,type              ENUM("OpenID") NOT NULL
    // ...

    PRIMARY_KEY(uid),type)
);

(在其他平台上,您将使用CHECK约束而不是ENUM.)MysqL supports复合外键,因此这应该适合您.

第一种方法是有效的,尽管你在那些可以使用NULL的列中浪费空间,因为它们的使用取决于用户的类型.优点是,如果您选择扩展要存储的类型的用户类型,并且这些类型不需要其他列,则只需展开ENUM的域并使用相同的表.

方式三强制任何引用用户检查两个表的查询.这也会阻止您通过外键引用单个用户表.

猜你在找的MsSQL相关文章