it-swarm-eu.dev

Jak lze mapovat vztah IS-A do databáze?

Zvažte následující:

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
}

Různé typy uživatelů (uživatelé s přímým přihlášením a uživatelé OpenID) zobrazují vztah IS-A; jmenovitě, že oba typy uživatelů jsou uživatelé. Nyní existuje několik způsobů, jak to lze reprezentovat v RDBMS:

Way One

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

Way Two

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
)

třetí způsob

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

Jsem si téměř jistý, že třetí cesta je špatná, protože není možné provést jednoduché připojení proti uživatelům jinde v databázi.

Příklad mého skutečného světa však není uživatelem s jiným příkladem přihlášení; Zajímalo by mě, jak modelovat tento vztah v obecném případě.

26
Billy ONeal

Způsob dva je správný způsob.

Vaše základní třída získá tabulku a potom podřízené třídy získají své vlastní tabulky pouze s dalšími poli, která zavedou, plus odkazy na cizí klíče v základní tabulce.

Jak Joel navrhl ve svých komentářích k této odpovědi, můžete zaručit, že uživatel bude mít buď přímé přihlášení nebo OpenID přihlášení, ale ne oba (a možná ani žádný) přidáním sloupce typu do každého podtyp tabulky, která klíče zpět do kořenové tabulky. Sloupec typu v každé tabulce podtypů je omezen na to, aby jedna hodnota představovala typ této tabulky. Protože tento sloupec je cizí klíč do kořenové tabulky, může se ke stejnému kořenovému řádku najednou připojit pouze jeden řádek podtypu.

Například by MySQL DDL vypadalo takto:

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

(Na jiných platformách byste místo CHECK použili omezení ENUM.) MySQL podporuje složené cizí klíče, takže by to mělo fungovat pro vás.

Jeden způsob je platný, i když zbytečně ztrácíte místo v těchto sloupcích NULLable, protože jejich použití závisí na typu uživatele. Výhodou je, že pokud se rozhodnete rozšířit, jaké typy uživatelských typů ukládat a tyto typy nevyžadují další sloupce, stačí rozšířit doménu ENUM a použít stejnou tabulku.

Třetí způsob vynutí všechny dotazy, které odkazují na uživatele, aby zkontrolovali obě tabulky. To také zabraňuje odkazování na tabulku jednoho uživatele pomocí cizího klíče.

16
Nick Chammas

Byly by pojmenovány

  1. Dědičnost jedné tabulky
  2. Dědičnost tabulky tříd
  3. Dědičnost betonové tabulky .

a všichni mají své legitimní použití a jsou podporovány některými knihovnami. Musíte zjistit, který se nejlépe hodí.

Pokud budete mít více tabulek, bude se správa dat více věnovat kódu vaší aplikace, ale sníží se tím množství nevyužitého prostoru.

5
flob