2010-09-09 12 views
4

J'essaie de déterminer la meilleure façon de mapper les relations d'héritage dans un modèle objet dans une base de données relationnelle. Considérons par exemple la structure de classe suivante.Stockage des objets hérités dans une base de données

public Class Item 
{ 
    public String Name{get; set;} 
    public int Size {get; set}  
} 

public Class Widget:Item 
{ 
    public String Color{get; set;} 
} 

public Class Doohicky:Item 
{ 
    public String Smell{get; set;} 
} 

Voici quelques options que je considère pour enregistrer cette structure dans une base de données.

Options 1: Table unique pour tous les types d'éléments

Items Table: ItemID, Name, Color, Smell 

Cette suce, car cela nécessiterait des valeurs NULL.

options 2: tables séparées pour chaque type d'élément

Widgets Table: WidgetID, Name, Color 
Doohicky Table: DoohickyID, Name, Smell 

Cela vaut mieux, mais serait plus difficile d'énumérer tous les articles

options 3: Tables liées

Items Table: ItemID (PK), Name, Size 
Widgets Table: WidgetID (PK), ItemID (FK), Color 
Doohicky Table: DoohickyID (PK), ItemID (FK), Smell 

Je pense que cette option est la meilleure, car elle m'empêche d'avoir des valeurs nulles dans tout champs, plus il sera plus facile de lister tous les éléments, et/ou de créer une liste d'un type spécifique d'élément (Widgets ou Doohickies).

Cependant, je ne sais pas comment créer la relation entre la table Items et les tables Widgets et Doohickies. Je ne veux pas finir avec une ligne dans l'une ou l'autre des tables référençant le même ItemID dans la table Items. Par exemple, lorsque j'ajoute une entrée à la table Widgets, comment puis-je m'assurer qu'elle est liée à une nouvelle entrée dans la table Items avec un ItemID unique? Dois-je à la place suivre uniquement l'ID d'élément plutôt que des ID spécifiques de type distincts tels que WidgetID et DoohickyID, et l'utiliser pour créer une relation un à un entre la table Items et les tables spécifiques au type?

Options de 4

Items Table: ItemID (PK), Name, Size 
Widgets Table: ItemID (PK), Color 
Doohicky Table: ItemID (PK), Smell 

Répondre

6

Vous décrivez Single-Table Inheritance, Concrete Table Inheritance et Class Table Inheritance.

Voir le classique livre Martin Fowler Patterns of Enterprise Application Architecture pour beaucoup d'informations à leur sujet. Une chose que vous pouvez faire pour vous assurer qu'un seul sous-type peut référencer le super-type est d'utiliser un champ ItemType. Une clé étrangère peut référencer les colonnes d'une contrainte UNIQUE ainsi qu'une clé primaire. Donc, vous pouvez ajouter Items.ItemType et faire une contrainte unique sur ItemID, ItemType. La clé étrangère dans chaque table de sous-types fait référence à cette clé unique à deux colonnes. Et puis vous pouvez contraindre le ItemType dans chaque table de sous-type pour avoir une certaine valeur. Ensuite, il doit correspondre à la valeur dans la table super-type, qui ne peut avoir qu'une seule valeur.

Items Table: ItemID (PK), ItemType, Name, Size 
    UNIQUE: (ItemID, ItemType) 
Widgets Table: ItemID (PK), ItemType, Color 
    FK: (ItemID, ItemType) 
    CHECK: ItemType=W 
Doohicky Table: ItemID (PK), ItemType, Smell 
    FK: (ItemID, ItemType) 
    CHECK: ItemType=D 
+0

Ahh cela aide beaucoup. Je voudrais vraiment suivre le modèle "Class Table Héritage". –

0

Avez-vous envisagé une solution NoSQL comme RavenDB ou MongoDB? Si vos besoins ne sont pas purement relationnels, une solution non relationnelle peut simplifier considérablement les choses.

0

Si vous concevez en gardant à l'esprit les classes actuelles, je préférerais que votre option 3 soit l'option préférée pour les raisons indiquées ci-dessus.

Re votre requête sur:

However, I'm not sure how to create the relationship between the Items table and the 
Widgets and Doohickies tables. I don't want to end up with row in either table 
referencing the same ItemID in the Items table. 

suggestion de Bill est au-dessus vraiment une bonne option. Quelque chose que je n'avais pas pensé :-) Cependant, je pensais que c'est une relation que vous pouvez appliquer soit dans votre code d'application lui-même ou en utilisant un déclencheur d'insertion. Je m'inquiète cependant de tenter de simuler l'héritage lui-même au niveau de la base de données.

Si le nombre de classes enfants est supposé croître sur une période de temps, ce type de conception de base de données peut devenir très difficile à maintenir.

En plus:

Items Table: ItemID (PK), Name, Size   
Widgets Table: WidgetID (PK), ItemID (FK), Color   
Doohicky Table: DoohickyID (PK), ItemID (FK), Smell   

Quelle est la probabilité de nouvelles classes comme les suivantes s'ajoutée?

DontDoHicky Table : DoohickyID (PK), ItemID (FK), Smell, **TASTE**   
MidWidget Table : WidgetID (PK), ItemID (FK), Color , **Height**   
MidDoHicky Table : WidgetID (PK), ItemID (FK), **Height**, **Smell** 

Ceci est bien sûr le problème classique de l'héritage OO. Si vous attendez l'application de croître comme celui-ci sur une période de temps et peut-être besoin de planifier au préalable, à un niveau DB, vous pouvez préférer aller avec une approche plus générique

Items Table: ItemID (PK), Name, Size, **ItemType**   
**ItemAttributes Table : ItemID (PK), AttributeID, AttributeName, AttributeValue**  

Cela vous permettra de appliquer votre contrainte de mappage 1: 1 facilement et vous permettre d'interroger facilement tous les attributs à l'aide de AttributeName tant que ceux-ci sont standard.

Ceci est probablement l'approche à l'ancienne et pas très orienté objet mais il pourrait être plus approprié en fonction de la flexibilité future.