Question

Exemple

J'ai Person, SpecialPerson, et User. Person et SpecialPerson sont juste des gens - qu'ils n'ont pas de nom d'utilisateur ou mot de passe sur un site, mais ils sont stockés dans une base de données pour la tenue des dossiers.L'utilisateur a tous les mêmes données Person et potentiellement SpecialPerson, avec un nom d'utilisateur et le mot de passe qu'ils sont inscrits sur le site.


Comment voulez-vous résoudre ce problème?Auriez-vous une Person le tableau qui stocke toutes les données commune pour une personne et utiliser une clé à rechercher leurs données dans SpecialPerson (si ils sont une personne spéciale) et l'Utilisateur (si ils sont d'un utilisateur) et vice-versa?

Était-ce utile?

La solution

Il y a généralement trois façons de l'objet de mappage de l'héritage de tables de base de données.

Vous pouvez faire une seule grande table avec tous les champs de tous les objets avec un champ spécial pour le type.C'est rapide, mais gaspille de l'espace, bien que des bases de données modernes économiser de l'espace en ne stockant pas les champs vides.Et si vous êtes seulement à la recherche de tous les utilisateurs dans la table, avec tous les types de personne dans les choses peuvent devenir lent.Pas tous les ou-mappeurs l'appui de cette.

Vous pouvez faire différentes tables pour tous les enfants des classes avec toutes les tables contenant les données de base des champs de classe.C'est ok à partir d'un point de vue performances.Mais pas à partir d'un point de vue de l'entretien.Chaque fois que votre classe de base change tout le changement de tables.

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

Ce que vous voulez utiliser dépend bien sur de votre situation.Aucune des solutions n'est parfaite, de sorte que vous avez à peser les avantages et les inconvénients.

Autres conseils

Jetez un oeil à Martin Fowler Les modèles de l'Architecture des Applications d'Entreprise:

  • Seul L'Héritage De Table:

    Lors du mappage d'une base de données relationnelle, nous essayons de réduire les jointures qui peut monter rapidement en place lors du traitement d'une structure d'héritage dans plusieurs tables.Seul l'Héritage de Table cartes de tous les champs de toutes les classes d'une structure d'héritage dans une seule table.

  • La Classe De L'Héritage De Table:

    Vous souhaitez structures de base de données que la carte clairement les objets et permettent d'établir des liens n'importe où dans la structure d'héritage.La classe de l'Héritage de Table prend en charge ce en utilisant une base de données d'une table par classe dans la structure d'héritage.

  • Le Béton De L'Héritage De Table:

    La pensée de tables à partir d'une instance de l'objet point de vue, un cheminement possible est de prendre chaque objet dans la mémoire et la carte en une seule ligne de base de données.Cela implique de Béton de l'Héritage de Table, où il y a une table pour chaque classe concrète dans la hiérarchie d'héritage.

Si l'Utilisateur, Personne et personne Spéciale, tous ont les mêmes clés étrangères, ensuite, j'aurais une seule table.Ajouter une colonne appelée Type qui est contraint d'être de l'Utilisateur, une Personne ou une Personne Spéciale.Puis, sur la base de la valeur de Type de contraintes sur les autres colonnes facultatives.

Pour le code de l'objet, il n'a pas beaucoup de différence si vous avez le des tables séparées ou plusieurs tables pour représenter le polymorphisme.Toutefois, si vous avez à faire SQL sur la base de données, est beaucoup plus facile si le polymorphisme est capturé dans un seul tableau...à condition que les clés étrangères pour les sous-types sont les mêmes.

Ce que je vais dire ici, c'est envoyer des architectes de base de données dans conniptions mais va ici:

Prenons une base de données vue comme l'équivalent d'une définition d'interface.Et d'un tableau est l'équivalent d'une classe.

Donc dans votre exemple, tous les 3 classes de la personne va mettre en œuvre l'interface IPerson.Vous avez donc 3 tables - un pour chacun des 'Utilisateur', 'Personne' et 'SpecialPerson'.

Ensuite d'avoir une vue "PersonView" ou tout ce qui sélectionne les propriétés communes (tel que défini par votre "interface") de tous les 3 tables dans la vue simple.L'utilisation d'un PersonType " colonne de ce point de vue pour stocker le type réel de la personne d'être stockés.

Ainsi, lorsque vous exécutez une requête qui peut être utilisé sur tout type de personne, il suffit de requête de la PersonView vue.

Cela pourrait ne pas être ce que l'OP voulais dire, mais j'ai pensé que je pourrais jeter ce ici.

J'ai récemment eu un cas unique de db polymorphisme dans un projet.Nous avons eu entre 60 à 120 classes possibles, chacun avec son propre ensemble de 30 à 40 attributs uniques, et environ 10 - 12 attributs communs à toutes les classes .Nous avons décidé d'aller le SQL-XML route et a terminé avec une seule table.Quelque chose comme :

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

contenant toutes les propriétés communes que les colonnes et puis une grande propriété XML sac.La couche ORM a ensuite été responsable de la lecture/écriture les propriétés respectives de la XMLOtherProperties.Un peu comme :

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

(nous avons terminé la cartographie de la colonne xml comme un Hastable plutôt que d'un document XML, mais vous pouvez utiliser tout ce qui convient à votre DAL meilleur)

Il ne va pas gagner un des prix de design, mais il ne fonctionnera que si vous avez un grand (ou inconnu) nombre de classes possibles.Et dans SQL2005 vous pouvez toujours utiliser XPATH dans vos requêtes SQL pour sélectionner des lignes en fonction de certains biens qui sont stockées au format XML..c'est juste une petite perte de performance à prendre en.

Il y a trois stratégies de base pour la manipulation de l'héritage dans une base de données relationnelle, et un certain nombre des plus complexes et/ou sur mesure des solutions de rechange en fonction de vos besoins précis.

  • Une Table par hiérarchie de classe.Une table pour l'ensemble de la hiérarchie.
  • Une Table par sous-classe.Un tableau distinct est créé pour chaque sous-classe avec un 0-1 association entre le sous-classé tables.
  • Une Table par classe concrète.Une table unique est créé pour chaque classe concrète.

Chacun de ces appoaches pose ses propres questions au sujet de la normalisation, du code d'accès aux données et le stockage de données, bien que mon choix est d'utiliser une table par sous-classe sauf si il y a une performance spécifique ou une raison structurelle pour aller avec l'une des solutions de rechange.

Au risque d'être une "architecture de l'astronaute" ici, je serais plus enclin à aller avec des tables séparées pour les sous-classes.La clé primaire de la sous-classe des tables aussi être une clé étrangère reliant à l'supertype.

La principale raison de cette façon de faire est qu'il devient alors beaucoup plus logiquement cohérent et ne pas se retrouver avec un grand nombre de champs qui sont NULS et non-sens de cet enregistrement particulier.Cette méthode rend également beaucoup plus facile d'ajouter des champs supplémentaires pour les sous-types comme vous itérer le processus de conception.

Cela ajoute la baisse de l'ajout de Rejoint à vos questions, ce qui peut influer sur les performances, mais j'ai presque toujours aller avec une conception idéale d'abord, et ensuite chercher à optimiser plus tard si cela s'avère nécessaire.Les quelques fois où je suis allé à la "optimale" abord, j'ai presque toujours regretté plus tard.

Donc, mon dessin ne serait pas quelque chose comme

PERSONNE (personid, nom, adresse, téléphone, ...)

SPECIALPERSON (personid les RÉFÉRENCES de la PERSONNE(personid), de champs supplémentaires...)

UTILISATEUR (personid les RÉFÉRENCES de la PERSONNE(personid), nom d'utilisateur, encryptedpassword, champs supplémentaires...)

Vous pouvez également créer des Vues plus tard, qui regroupe le supertype et le sous-type, si c'est nécessaire.

Le seul défaut de cette approche est que si vous vous trouvez fortement à la recherche pour les sous-types associés avec un particulare supertype.Il n'y a pas de réponse facile à ce sur le dessus de ma tête, vous pouvez suivre par programmation si nécessaire, ou bien exécuter un certain requêtes globales et mettre en cache les résultats.Il va vraiment dépendre de l'application.

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

Je voudrais créer une table Utilisateur, une Personne de la table qui a un nullable champ de clé étrangère à l'Utilisateur (j'.e, la Personne peut être un Utilisateur, mais ne doit pas).
Puis je ferais un SpecialPerson table qui se rapporte à la Personne de la table avec tous les champs supplémentaires en elle.Si un enregistrement est présent dans SpecialPerson pour une Personne donnée.ID, il/elle est une personne spéciale.

Dans notre entreprise, nous avons affaire avec le polymorphisme par la combinaison de tous les champs d'une table et à son pire et pas l'intégrité référentielle peut être appliqué et très difficiles à comprendre le modèle.Je déconseille cette approche pour vous.

Je voudrais aller avec une Table par sous-classe, et aussi d'éviter de performances, mais à l'aide de l'ORM où l'on peut éviter de s'unir avec toutes les classes de tableaux par la construction de requêtes à la volée en se basant sur le type.Cette stratégie fonctionne pour un seul niveau record de traction, mais pour la mise à jour en bloc ou sélectionnez vous ne pouvez pas l'éviter.

oui, je voudrais également envisager une TypeID avec un PersonType table, si c'est possible, il y aura de plus en plus de types.Cependant, si il n'y a que 3 qui ne devrait pas être nec.

C'est un vieux post, mais je pense que je vais peser dans un conceptuelles, procédurales et de point de vue des performances.

La première question que je voudrais poser est la relation entre la personne, specialperson, et l'utilisateur, et si c'est possible pour quelqu'un d'être les deux un specialperson et un utilisateur simultanément.Ou, tout autre de 4 combinaisons possibles (catégorie a + b, classe b + c, classe a + c ou a + b + c).Si cette classe est stockée en tant que valeur dans un type champ et donc de réduire ces combinaisons, et que l'effondrement est inacceptable, alors je pense que d'une table secondaire serait nécessaire permettant un un-à-plusieurs relations.J'ai appris que vous ne jugez pas que jusqu'à ce que vous évaluer l'utilisation et le coût de la perte de votre combinaison de l'information.

L'autre facteur qui me fait pencher vers une seule table est la description du scénario. User est la seule entité avec un nom d'utilisateur (dites de type varchar(30)) et le mot de passe (dites de type varchar(32)).Si le commun des champs " longueur possible est une moyenne de 20 caractères par 20 champs, puis votre colonne augmentation de la taille est de 62 plus de 400, soit environ 15% - il y a 10 ans, cela aurait été plus coûteuse que c'est moderne, avec des systèmes SGBDR, surtout avec un champ de type varchar (par ex.pour MySQL) disponibles.

Et, si la sécurité est une préoccupation pour vous, il pourrait être avantageux d'avoir un secondaire à une table appelée credentials ( user_id, username, password).Ce tableau serait invoquée dans une JOINTURE contextuellement à dire moment de la connexion, mais structurellement distincte de juste "quelqu'un" dans la table principale.Et, un LEFT JOIN est disponible pour les requêtes qui pourraient vouloir envisager des "utilisateurs enregistrés".

Mon compte principal pour ans est toujours à considérer l'objet de la signification (et, par conséquent, possible de l'évolution) à l'extérieur de la DB et dans le monde réel.Dans ce cas, tous les types de personnes ont battement de coeur (je l'espère), et peut également avoir des relations hiérarchiques de l'un à l'autre;ainsi, dans le dos de mon esprit, même si ce n'est maintenant, nous pouvons avoir besoin de stocker ces relations par une autre méthode.Ce n'est pas explicitement liée à votre question ici, mais il est un autre exemple de l'expression d'un objet de la relation.Et, aujourd'hui (7 ans plus tard), vous devriez avoir un bon aperçu de la façon dont votre décision travaillé de toute façon :)

Dans le passé, j'ai fait exactement comme vous le suggérez, -- avoir une Personne de la table pour le commun des trucs, puis SpecialPerson liés pour la classe dérivée.Cependant, je suis re-penser que, comme Linq2Sql veut avoir un champ dans la table indiquent la différence.Je n'ai pas regardé le modèle d'entité trop, si -- assez sûr que l'une permet à l'autre méthode.

Personnellement, je voudrais stocker l'ensemble de ces différentes classes d'utilisateurs dans une table unique.Ensuite, vous pouvez soit avoir un champ qui stocke un "Type" de la valeur, ou vous pouvez impliquent quel type de personne que vous faites affaire avec par ce que les champs sont remplis.Par exemple, si le nom d'utilisateur est NULLE, alors ce record n'est pas un Utilisateur.

Vous pouvez lier à d'autres tables à l'aide d'un-à-un-ou-rien, le type de jointure, mais ensuite, dans chaque requête, vous serez en ajoutant plus de jointures.

La première méthode est également pris en charge par LINQ-to-SQL si vous décidez d'aller dans cette voie (ils l'appellent "une Table Par Hiérarchie" ou "TPH').

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top