IS-A ilişkisini bir veritabanında nasıl eşlerim?


26

Aşağıdakileri göz önünde bulundur:

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
}

Farklı türde kullanıcılar (Doğrudan Giriş kullanıcıları ve OpenID kullanıcıları) bir IS-A ilişkisi gösterir; yani, her iki kullanıcı türünün de kullanıcı olduğu. Şimdi bunun bir RDBMS'de gösterilebileceği birkaç yol var:

Bir yol

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

Yol iki

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
)

Yol üç

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

Neredeyse üçüncü yolun yanlış yol olduğundan eminim, çünkü veritabanındaki herhangi bir yerdeki kullanıcılara basit bir katılım mümkün değil.

Benim gerçek dünya örneğim, farklı giriş örnekleri olan bir kullanıcı olmasa da; Bu durumun genel durumda nasıl modelleneceği ile ilgileniyorum.


Cevabımı Joel Brown tarafından yorumlarda öne sürülen yaklaşımı içerecek şekilde değiştirdim. Senin için çalışmalı. Daha fazla öneri arıyorsanız, MySQL'e özel bir cevap aradığınızı belirtmek için sorunuzu yeniden etiketlerim.
Nick Chammas

Not, gerçekten ilişkilerin veritabanının geri kalanında nasıl kullanıldığına bağlı. Çocuk varlıkları içeren ilişkiler, sadece bu tablolara yabancı anahtarlar gerektirir ve bazı teklikler olmadan tek bir birleştirici tabloya eşlenmesini yasaklar.
Beldaz

PostgreSQL gibi nesne-ilişkisel veritabanlarında, aslında dördüncü bir yol var: INHERITS tablosunu başka bir tablodan ilan edebilirsiniz. postgresql.org/docs/current/static/tutorial-inheritance.html
MarkusSchaber

Yanıtlar:


16

İkinci yol doğru yoldur.

Temel sınıfınız bir masa alır ve daha sonra alt sınıflar tanıttıkları ek alanların yanı sıra temel tabloya yabancı anahtar başvuruları ile kendi tablolarını alır.

Joel'in bu cevap hakkındaki yorumunda önerdiği gibi , bir kullanıcının ya doğrudan giriş yapmasını ya da bir OpenID girişini yapmasını garanti edersiniz, ancak geri dönen her bir alt tip tablosuna bir tür sütunu ekleyerek ikisinin de (ve muhtemelen ikisinin de değil) olacağını garanti edebilirsiniz. kök tabloya. Her bir alt-tip tablosundaki tip sütunu, o tablonun tipini temsil eden tek bir değere sahip olacak şekilde sınırlandırılmıştır. Bu sütun kök tablaya yabancı olduğundan, aynı anda yalnızca bir alt tip satır aynı kök satırına bağlanabilir.

Örneğin, MySQL DDL şöyle bir şeye benzeyebilir:

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

(Diğer platformlarda CHECKbunun yerine bir kısıtlama kullanırsınız ENUM.) MySQL , bileşik yabancı anahtarları desteklediğinden sizin için çalışması gerekir.

Bunlardan biri geçerli, bu NULLsütunları boşa harcıyor olsanız da, bunların kullanımları kullanıcının türüne bağlı olarak değişiyor. Bunun avantajı, hangi tür kullanıcı türlerini depolamak için genişletmeyi seçmeniz ve bu türlerin ek sütunlar gerektirmemesi durumunda, alanınızın alanını genişletip ENUMaynı tabloyu kullanabilmenizdir.

Üçüncüsü, kullanıcılara her iki tabloyu da kontrol etmesi için başvuruda bulunan sorguları zorlar. Bu aynı zamanda tek bir kullanıcı tablosuna yabancı anahtar ile atıfta bulunmanızı önler.


1
Yol 2'yi kullanarak, diğer iki tabloda da tam olarak karşılık gelen bir satır olduğunu zorlamanın bir yolu olmadığı gerçeğiyle nasıl başa çıkabilirim?
Billy ONeal

2
@Billy - İyi itiraz. Kullanıcılarınızda yalnızca biri veya diğeri olabilirse, bunu proc katmanınız veya tetikleyicileriniz aracılığıyla zorlayabilirsiniz. Bu kısıtlamayı uygulamak için DDL düzeyinde bir yol olup olmadığını merak ediyorum. (Ne yazık ki, dizinli görünümler izin vermez UNION , ya da ben karşı benzersiz bir dizin dizin oluşturulmuş görünümü önerdi olurdu UNION ALLait uidiki tablolardan.)
Nick Chammas

Tabii ki, RDBMS'nizin her şeyden önce dizine alınmış görünümleri desteklediğini varsayar.
Billy ONeal

1
Bu tür bir çapraz tablo kısıtlamasını uygulamak için kullanışlı bir yol, süper tip tabloya bir bölümleme niteliği eklemek olacaktır. Daha sonra her bir alt tip, sadece uygun bölümleme öznitelik değerine sahip süper tiplerle ilgili olup olmadığını kontrol edebilir. Bu, bir veya daha fazla başka alt tip tabloya bakarak bir çarpışma testi yapmak zorunda kalmaz.
Joel Brown

1
@Joel - Mesela, örneğin, typeher bir alt-tip tabloya, kısıtlama ile CHECKsınırlandırılmış bir tam değere (o tablonun tipi) sahip bir sütun ekleriz . Sonra ikimiz de kompozit olanları içine süper tabloya alt tablo yabancı anahtarları yapmak uidve type. Zekice.
Nick Chammas

5

Onlar isimlendirilirdi

  1. Tek Tablo Kalıtım
  2. Sınıf Tablo Mirası
  3. Beton Tablo Kalıtım .

ve hepsinin meşru kullanımları vardır ve bazı kütüphaneler tarafından desteklenir. Hangisinin en uygun olduğunu bulmak zorundasın.

Birden fazla tablo olması veri yönetimini uygulama kodunuza daha fazla götürür, ancak kullanılmayan alanı azaltır.


2
"Paylaşılan Birincil Anahtar" adlı ek bir teknik var. Bu teknikte, alt sınıf tabloları bağımsız olarak atanmış bir birincil anahtar kimliğine sahip değildir. Bunun yerine, alt sınıf tabloların PK'si, üst sınıf tabloya başvuran FK'dır. Bu, temel olarak IS-A ilişkilerinin bire bir niteliğini zorlaması için birçok fayda sağlar. Bu teknik Class Table Mirasına bir katkıdır.
Walter Mitty
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.