49 votes

Comment gérer le polymorphisme dans une base de données ?

Exemple

J'ai Person , SpecialPerson y User . Person y SpecialPerson ne sont que des personnes - elles n'ont pas de nom d'utilisateur ni de mot de passe sur un site, mais elles sont stockées dans une base de données pour la tenue des dossiers. L'utilisateur possède toutes les mêmes données que Person et potentiellement SpecialPerson ainsi qu'un nom d'utilisateur et un mot de passe tels qu'ils sont enregistrés sur le site.


Comment aborderiez-vous ce problème ? Auriez-vous un Person qui stocke toutes les données communes à une personne et utilise une clé pour rechercher ses données dans SpecialPerson (si elle est une personne spéciale) et Utilisateur (si elle est un utilisateur) et vice-versa ?

50voto

Vitor Silva Points 4804

42voto

Mendelt Points 21583

Il existe généralement trois façons de mettre en correspondance l'héritage des objets avec les tables de la base de données.

Vous pouvez créer un grand tableau avec tous les champs de tous les objets, avec un champ spécial pour le type. C'est rapide mais cela fait perdre de l'espace. Bien que les bases de données modernes économisent de l'espace en ne stockant pas les champs vides. Et si vous ne cherchez que tous les utilisateurs dans la table avec chaque type de personne, les choses peuvent devenir lentes. Tous les or-mappers ne supportent pas cela.

Vous pouvez créer des tables différentes pour toutes les différentes classes enfantines, toutes les tables contenant les champs de la classe de base. Cela est acceptable du point de vue des performances. Mais pas du point de vue de la maintenance. Chaque fois que votre classe de base change, toutes les tables changent.

Vous pouvez aussi faire un tableau par classe comme vous l'avez suggéré. De cette façon, vous avez besoin de jointures pour obtenir toutes les données. C'est donc moins performant. Je pense que c'est la solution la plus propre.

Ce que vous souhaitez utiliser dépend bien sûr de votre situation. Aucune des solutions n'est parfaite, vous devez donc peser le pour et le contre.

6voto

Mat Roberts Points 43

Si l'utilisateur, la personne et la personne spéciale ont tous les mêmes clés étrangères, alors j'aurais une seule table. Ajoutez une colonne appelée Type qui doit être Utilisateur, Personne ou Personne spéciale. Ensuite, en fonction de la valeur de Type, il y a des contraintes sur les autres colonnes facultatives.

Pour le code objet, cela ne fait pas de différence si vous avez des tables séparées ou des tables multiples pour représenter le polymorphisme. Cependant, si vous devez faire du SQL avec la base de données, c'est beaucoup plus facile si le polymorphisme est capturé dans une seule table... à condition que les clés étrangères pour les sous-types soient les mêmes.

5voto

Radu094 Points 7796

Ce n'est peut-être pas ce que l'OP voulait demander, mais j'ai pensé que je pourrais le faire ici.

J'ai récemment été confronté à un cas unique de polymorphisme db dans un projet. Nous avions entre 60 et 120 classes possibles, chacune avec son propre ensemble de 30 à 40 attributs uniques, et environ 10 à 12 attributs communs à toutes les classes. Nous avons décidé de suivre la voie SQL-XML et nous nous sommes retrouvés avec une seule table. Quelque chose comme :

PERSON (personid,persontype, name,address, phone, XMLOtherProperties)

contenant toutes les propriétés communes sous forme de colonnes, puis un grand sac de propriétés XML. La couche ORM était alors responsable de la lecture/écriture des propriétés respectives à partir du XMLOtherProperties. Un peu comme :

 public string StrangeProperty
{
get { return XMLPropertyBag["StrangeProperty"];}
set { XMLPropertyBag["StrangeProperty"]= value;}
}

(nous avons fini par mapper la colonne xml comme un Hastable plutôt qu'un doc XML, mais vous pouvez utiliser ce qui convient le mieux à votre DAL)

Ce système ne gagnera pas de prix de design, mais il fonctionnera si vous avez un nombre important (ou inconnu) de classes possibles. Et en SQL2005, vous pouvez toujours utiliser XPATH dans vos requêtes SQL pour sélectionner des lignes sur la base d'une propriété stockée en XML c'est juste une petite pénalité de performance à prendre en compte.

3voto

Lars Mæhlum Points 4569

Je dirais que, selon ce qui différencie Person et Special Person, vous ne voulez probablement pas de polymorphisme pour cette tâche.

Je crée une table Utilisateur, une table Personne qui possède un champ de clé étrangère nullable pour Utilisateur (c'est-à-dire que la Personne peut être un Utilisateur, mais ne doit pas l'être).
Ensuite, je créerais une table SpecialPerson qui se rapporte à la table Person avec tous les champs supplémentaires qu'elle contient. Si un enregistrement est présent dans SpecialPerson pour un ID de personne donné, il/elle est une personne spéciale.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X