数据库设计 – 如何将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的域并使用相同的表. 方式三强制任何引用用户检查两个表的查询.这也会阻止您通过外键引用单个用户表. (编辑:上饶站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |