it-swarm.asia

Bagaimana cara memetakan hubungan IS-A ke dalam basis data?

Pertimbangkan yang berikut ini:

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
}

Berbagai jenis pengguna (pengguna Login Langsung, dan pengguna OpenID) menampilkan hubungan IS-A; yaitu, bahwa kedua jenis pengguna adalah pengguna. Sekarang, ada beberapa cara ini dapat direpresentasikan dalam 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
)

Way Three

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

Saya hampir yakin cara ketiga adalah cara yang salah, karena tidak mungkin untuk melakukan join sederhana terhadap pengguna di tempat lain dalam database.

Contoh dunia nyata saya bukan pengguna dengan contoh login berbeda; Saya tertarik bagaimana memodelkan hubungan ini dalam kasus umum.

26
Billy ONeal

Cara kedua adalah cara yang benar.

Kelas dasar Anda mendapatkan tabel, dan kemudian kelas anak mendapatkan tabel mereka sendiri hanya dengan bidang tambahan yang mereka perkenalkan, ditambah referensi kunci asing ke tabel dasar.

Seperti Joel yang disarankan dalam komentarnya pada jawaban ini, Anda dapat menjamin bahwa pengguna akan memiliki login langsung atau login OpenID, tetapi tidak keduanya (dan juga mungkin juga tidak) dengan menambahkan kolom jenis ke setiap sub-jenis tabel yang mengembalikan kunci ke tabel root. Kolom tipe di setiap sub-tipe tabel dibatasi untuk memiliki nilai tunggal yang mewakili tipe tabel itu. Karena kolom ini adalah kunci asing ke tabel akar, hanya satu baris sub-jenis yang dapat menautkan ke baris akar yang sama pada suatu waktu.

Sebagai contoh, MySQL DDL akan terlihat seperti:

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

(Pada platform lain Anda akan menggunakan batasan CHECK alih-alih ENUM.) MySQL mendukung kunci asing komposit jadi ini seharusnya bekerja untuk Anda.

Cara satu valid, meskipun Anda membuang-buang ruang di kolom NULL- tersebut karena penggunaannya bergantung pada jenis pengguna. Keuntungannya adalah jika Anda memilih untuk memperluas jenis pengguna apa yang akan disimpan dan jenis-jenis itu tidak memerlukan kolom tambahan, Anda bisa memperluas domain ENUM Anda dan menggunakan tabel yang sama.

Cara ketiga memaksa kueri yang merujuk pengguna untuk memeriksa kedua tabel. Ini juga mencegah Anda merujuk tabel pengguna tunggal melalui kunci asing.

16
Nick Chammas

Mereka akan diberi nama

  1. Single Table Inheritance
  2. Class Table Inheritance
  3. Warisan Tabel Beton .

dan semua memiliki kegunaan yang sah dan didukung oleh beberapa perpustakaan. Anda harus mencari tahu mana yang paling cocok.

Memiliki beberapa tabel akan membuat manajemen data lebih memperhatikan kode aplikasi Anda tetapi akan mengurangi jumlah ruang yang tidak digunakan.

5
flob