Folgendes berücksichtigen:
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
}
Die verschiedenen Benutzertypen (Direktanmeldebenutzer und OpenID-Benutzer) zeigen eine IS-A-Beziehung an. nämlich, dass beide Benutzertypen Benutzer sind. Nun gibt es verschiedene Möglichkeiten, wie dies in einem RDBMS dargestellt werden kann:
Weg Eins
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)
)
Weg Zwei
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
)
Weise drei
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)
)
Ich bin mir fast sicher, dass der dritte Weg der falsche ist, da es nicht möglich ist, einen einfachen Join gegen andere Benutzer in der Datenbank durchzuführen.
Mein reales Beispiel ist jedoch kein Benutzer mit einem anderen Anmeldebeispiel. Mich interessiert, wie man diese Beziehung im allgemeinen Fall modelliert.
database-design
Billy ONeal
quelle
quelle
Antworten:
Weg zwei ist der richtige Weg.
Ihre Basisklasse erhält eine Tabelle, und dann erhalten untergeordnete Klassen ihre eigenen Tabellen mit nur den zusätzlichen Feldern, die sie einführen, sowie Fremdschlüsselverweisen auf die Basistabelle.
Wie Joel in seinen Kommentaren zu dieser Antwort vorgeschlagen hat, können Sie sicherstellen, dass ein Benutzer entweder eine direkte Anmeldung oder eine OpenID-Anmeldung hat, jedoch nicht beide (und möglicherweise auch keine), indem Sie jeder Subtyp-Tabelle, die zurückschlüsselt, eine Typenspalte hinzufügen an die Wurzeltabelle. Die Typenspalte in jeder Untertypentabelle darf nur einen einzigen Wert enthalten, der den Typ dieser Tabelle darstellt. Da diese Spalte mit einem Fremdschlüssel für die Stammtabelle versehen ist, kann jeweils nur eine Untertypzeile mit derselben Stammzeile verknüpft werden.
Zum Beispiel würde die MySQL-DDL ungefähr so aussehen:
(Auf anderen Plattformen würden Sie
CHECK
stattdessen eine Einschränkung verwendenENUM
.) MySQL unterstützt zusammengesetzte Fremdschlüssel, sodass dies für Sie funktionieren sollte.Der
NULL
erste Weg ist gültig, obwohl Sie in diesen Spalten Platz verschwenden, da ihre Verwendung vom Benutzertyp abhängt. Der Vorteil ist, dass Sie, wenn Sie festlegen, welche Benutzertypen gespeichert werden sollen und für diese Typen keine zusätzlichen Spalten erforderlich sind, einfach die Domäne erweiternENUM
und dieselbe Tabelle verwenden können.Methode drei erzwingt, dass Abfragen, die auf Benutzer verweisen, mit beiden Tabellen abgeglichen werden. Dies verhindert auch, dass Sie über einen Fremdschlüssel auf eine einzelne Benutzertabelle verweisen.
quelle
UNION
, oder ich hätte eine indizierte Ansicht mit einem eindeutigen Index gegen dasUNION ALL
vonuid
aus den beiden Tabellen vorgeschlagen.)type
jeder Untertyp -Tabelle eine Spalte hinzu, die über eineCHECK
Einschränkung auf genau einen Wert (den Typ dieser Tabelle) beschränkt ist. Dann machen wir die Fremdschlüssel der Subtabelle zur Supertabelle auf beidenuid
und zu zusammengesetzten Schlüsselntype
. Das ist genial.Sie würden benannt werden
und alle haben ihre legitimen Verwendungen und werden von einigen Bibliotheken unterstützt. Sie müssen herausfinden, welche am besten passt.
Wenn Sie mehrere Tabellen haben, wird die Datenverwaltung stärker auf Ihren Anwendungscode angewendet, der ungenutzte Speicherplatz wird jedoch verringert.
quelle