Considérer ce qui suit:
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
}
Les différents types d'utilisateurs (utilisateurs à connexion directe et utilisateurs OpenID) affichent une relation IS-A; à savoir que les deux types d'utilisateurs sont des utilisateurs. Maintenant, il existe plusieurs façons de représenter cela dans un SGBDR:
Première voie
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)
)
Deuxième voie
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
)
Troisième voie
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)
)
Je suis presque certain que la troisième voie est la mauvaise, car il n'est pas possible de faire une simple jointure contre des utilisateurs ailleurs dans la base de données.
Mon exemple dans le monde réel n'est pas un exemple d'utilisateurs avec des connexions différentes; Je souhaite savoir comment modéliser cette relation dans le cas général.
database-design
Billy ONeal
la source
la source
Réponses:
La deuxième façon est la bonne.
Votre classe de base obtient une table, puis les classes enfants obtiennent leurs propres tables avec uniquement les champs supplémentaires qu'elles introduisent, ainsi que les références de clé étrangère à la table de base.
Comme Joel l'a suggéré dans ses commentaires sur cette réponse, vous pouvez garantir qu'un utilisateur aura soit une connexion directe, soit une connexion OpenID, mais pas les deux (et peut-être même ni l'un ni l'autre) en ajoutant une colonne de type à chaque table de sous-type qui revient en arrière. à la table racine. La colonne type de chaque table de sous-type est limitée à une seule valeur représentant le type de cette table. Étant donné que cette colonne est dotée d'une clé étrangère pour la table racine, une seule ligne de sous-type peut être liée à la même ligne racine à la fois.
Par exemple, le DDL MySQL ressemblerait à quelque chose comme:
(Sur d'autres plates-formes, vous utiliseriez une
CHECK
contrainte au lieu deENUM
.) MySQL prend en charge les clés étrangères composites, cela devrait donc fonctionner pour vous.La première façon est valide, bien que vous gaspilliez de l'espace dans ces
NULL
colonnes activables car leur utilisation dépend du type d'utilisateur. L'avantage est que si vous choisissez d'étendre les types de types d'utilisateurs à stocker et que ces types ne nécessitent pas de colonnes supplémentaires, vous pouvez simplement développer le domaine de votreENUM
et utiliser la même table.La troisième méthode force toutes les requêtes qui référencent les utilisateurs à comparer avec les deux tables. Cela vous empêche également de référencer une table d'utilisateurs unique via une clé étrangère.
la source
UNION
, ou j'aurais suggéré une vue indexée avec un index unique par rapport auxUNION ALL
deuid
des deux tables.)type
colonne à chaque table de sous-type qui est restreinte via uneCHECK
contrainte pour avoir exactement une valeur (le type de cette table). Ensuite, nous transformons les clés étrangères de la sous-table de la super-table en clés composites suruid
ettype
. C'est ingénieux.Ils seraient nommés
et tous ont leurs utilisations légitimes et sont pris en charge par certaines bibliothèques. Vous devez trouver celle qui vous convient le mieux.
Avoir plusieurs tables rendrait la gestion des données plus importante pour votre code d'application, mais réduirait la quantité d'espace inutilisé.
la source