it-swarm-eu.dev

Wie ordne ich eine IS-A-Beziehung einer Datenbank zu?

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 (Direct Login-Benutzer und OpenID-Benutzer) zeigen eine IS-A-Beziehung an. nämlich, dass beide Arten von Benutzern Benutzer sind. Es gibt 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
)

Weg 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 Benutzer an anderer Stelle in der Datenbank durchzuführen.

Mein Beispiel aus der realen Welt ist jedoch kein Beispiel für Benutzer mit unterschiedlichen Anmeldungen. Ich bin daran interessiert, wie diese Beziehung im allgemeinen Fall modelliert werden kann.

26
Billy ONeal

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üsselreferenzen auf die Basistabelle.

Wie Joel in seinen Kommentaren zu dieser Antwort vorgeschlagen hat, können Sie garantieren, dass ein Benutzer entweder eine direkte Anmeldung oder eine OpenID-Anmeldung hat, jedoch nicht beide (und möglicherweise auch keine), indem Sie jeder eine Typspalte hinzufügen Untertyp-Tabelle, die auf die Stammtabelle zurückgreift. Die Typspalte in jeder Untertypentabelle darf nur einen einzigen Wert haben, 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:

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)
);

(Auf anderen Plattformen würden Sie eine CHECK -Einschränkung anstelle von ENUM verwenden.) MySQL nterstützt zusammengesetzte Fremdschlüssel, sodass dies für Sie funktionieren sollte.

Die erste Methode ist gültig, obwohl Sie Speicherplatz in diesen NULL -fähigen Spalten verschwenden, da ihre Verwendung vom Benutzertyp abhängt. Der Vorteil ist, dass Sie, wenn Sie erweitern möchten, welche Arten von Benutzertypen gespeichert werden sollen und für diese Typen keine zusätzlichen Spalten erforderlich sind, einfach die Domäne Ihres ENUM erweitern und dieselbe Tabelle verwenden können.

Weg drei zwingt alle Abfragen, die Benutzer referenzieren, mit beiden Tabellen zu vergleichen. Dies verhindert auch, dass Sie über einen Fremdschlüssel auf eine einzelne Benutzertabelle verweisen.

16
Nick Chammas

Sie würden benannt werden

  1. Single Table Inheritance
  2. Vererbung der Klassentabelle
  3. Konkrete Tabellenvererbung .

und alle haben ihre legitimen Verwendungszwecke und werden von einigen Bibliotheken unterstützt. Sie müssen herausfinden, welche am besten passt.

Wenn mehrere Tabellen vorhanden sind, wird die Datenverwaltung stärker auf Ihren Anwendungscode übertragen, der nicht verwendete Speicherplatz wird jedoch reduziert.

5
flob