Question

J'ai des produits qui appartiennent à la catégorie.

Chaque catégorie peut avoir différentes propriétés.

Par exemple,

  • la catégorie voitures a les propriétés couleur , pouvoir, ...
  • la catégorie les animaux ont les propriétés poids , âge , ...

Le nombre de catégories est d'environ 10-15. Le nombre de propriétés dans chaque catégorie est 3-15. Le nombre de produits est très grand.

La principale exigence pour cette application est une très bonne recherche. Nous allons sélectionner une catégorie et entrer des critères pour chaque propriété de cette catégorie.

Doit concevoir la base de données pour ce scénario. (SQL Server 2005)

Était-ce utile?

La solution

L'approche de conception classique serait (l'étoile désigne la colonne de clé primaire):

Product
  ProductId*
  CategoryId: FK to Category.CategroyId
  Name

Category
  CategoryId*
  Name

Property
  PropertyId*
  Name
  Type

CategoryProperty
  CategoryId*: FK to Category.CategoryId
  PropertyId*: FK to Property.PropertyId

ProductProperty
  ProductId*: FK to Product.ProductId
  PropertyId*: FK to Property.PropertyId
  ValueAsString

Si vous pouvez accepter le fait que chaque valeur de propriété va à la base de données en tant que chaîne et que les informations de conversion de type sont stockées dans la table des propriétés, cette présentation suffira.

La requête ressemblerait à ceci:

SELECT
   Product.ProductId,
   Product.Name AS ProductName,
   Category.CategoryId,
   Category.Name AS CategoryName,
   Property.PropertyId,
   Property.Name AS PropertyName,
   Property.Type AS PropertyType,
   ProductProperty.ValueAsString
FROM
   Product 
   INNER JOIN Category         ON Category.CategoryId = Product.CategoryId
   INENR JOIN CategoryProperty ON CategoryProperty.CategoryId = Category.CategoryId
   INNER JOIN Property         ON Property.PropertyId = CategoryProperty.PropertyId
   INNER JOIN ProductProperty  ON ProductProperty.PropertyId = Property.PropertyId
                                  AND ProductProperty.ProductId = Product.ProductId
WHERE
   Product.ProductId = 1

Plus vous fournissez de conditions WHERE (conjointement, par exemple, en utilisant AND), plus la requête sera rapide. Si vous avez correctement indexé vos tables, c'est.

Dans l'état actuel des choses, la solution n'est pas idéale pour une situation d'indexation de texte intégral. Une table supplémentaire qui stocke tout le texte associé à un ProductId de manière plus dénormalisée pourrait aider ici. Cette table nécessiterait une mise à jour via des déclencheurs qui écoutent les modifications apportées à la table ProductProperty.

Autres conseils

Si l'utilisateur de l'application doit sélectionner une catégorie avant de pouvoir effectuer une recherche, je séparerais vos produits dans différentes tables de base de données par catégorie. Cette solution est également indiquée par le fait que les catégories elles-mêmes ont si peu en commun. La ventilation par catégorie accélérera également chaque recherche, car vous ne perdez pas de temps à chercher dans les voitures lorsque votre utilisateur recherche un animal domestique.

Une fois les produits divisés en catégories, il devrait être facile de créer les tableaux en utilisant les propriétés communes des produits de chaque catégorie. L’interface utilisateur de votre application doit être dynamique (je pense à un formulaire Web), en ce sens que les propriétés que l’utilisateur peut choisir doivent changer lorsque l’utilisateur sélectionne une catégorie.

Veuillez noter que si vous souhaitez répertorier des produits dans plusieurs catégories, cette solution entraînera la duplication des données dans vos tableaux. Il y a un compromis entre vitesse et normalisation lors de la conception d'une base de données. Si vous n'avez pas de produits pouvant être classés dans plusieurs catégories, alors je pense que ce sera la solution la plus rapide (en termes de vitesse de recherche).

La plupart des gens conseillent d'utiliser des variantes de la conception EAV (Entity-Attribute-Value). Cette conception est excessive pour votre situation et introduit de nombreux problèmes, par exemple:

  • Vous ne pouvez pas définir le type de données d'un attribut. vous pouvez entrer " banane " pour un attribut entier
  • Vous ne pouvez pas déclarer un attribut comme obligatoire (c'est-à-dire NOT NULL dans une table conventionnelle)
  • Vous ne pouvez pas déclarer une contrainte de clé étrangère sur un attribut

Si vous avez un petit nombre de catégories, il est préférable d'utiliser la solution A dans la réponse de Bogdan Maxim. En d’autres termes, définissez une table avec des attributs communs à toutes les catégories et une table supplémentaire pour chaque catégorie afin de stocker les attributs spécifiques à la catégorie.

EAV est une bonne solution si vous avez un nombre infini de catégories ou si vous devez potentiellement prendre en charge un ensemble d'attributs différent par ligne dans Products. Mais vous n'utilisez pas du tout une base de données relationnelle, car EAV enfreint plusieurs règles de normalisation.

Si vous avez vraiment besoin de cette souplesse, stockez vos données au format XML. En fait, vous pourriez vous pencher sur des frameworks RDF et du Web sémantique tels que Sesame .

Vous pouvez envisager un type de entité-attribut-valeur . arrangement, où vous pouvez & "taguer &"; chaque produit avec des paires d'attributs nom / valeur arbitraires.

Vous pouvez essayer ceci. Je ne suis pas trop sûr des détails de votre question. Peut-être que quelqu'un pourra vous aider à traduire un peu mieux.

5 tables. 3 pour stocker les données, 2 pour stocker les mappages entre les données.

tProduct 
  productID
  <other product details>

tCategory
  categoryID
  <other category details>

tProperty
  propertyID
  <other property details>

tProductXCategory
  productyID
  categoryID

tCategoryXProperty
  categoryID
  propertyID

Vos requêtes devront associer les données à l'aide des tables de mappage, mais cela vous permettra de créer différentes relations entre plusieurs catégories entre catégories, propriétés et produits.

Utilisez des procédures stockées ou des requêtes paramétrées pour optimiser les performances de vos recherches.

Si vous souhaitez faire preuve de souplesse dans vos catégories et propriétés, vous devez créer les tableaux suivants:

  • produit: ID de produit
  • catégorie: ID de catégorie, ID de produit
  • property: PropertyID, CategoryID

lorsque vous souhaitez partager une catégorie sur plusieurs produits, vous devez créer une table de liens pour la jointure n: m:

  • productCategoryPointer: ProdCatID, ProductID, CategoryID.

Vous devrez faire des jointures dans vos requêtes, mais avec les bons index, vous devriez pouvoir interroger rapidement vos données.

Vous pouvez essayer quelque chose de plus orienté objet.

1. Définir une table de base pour les produits

Products(ProductID, CategoryID, <any other common properties>)

2. Définir une table Catégories

Categories(CategoryID, Name, Description, ..)

À partir de là, vous avez beaucoup d'options et la quasi-totalité d'entre elles interrompront la normalisation de votre base de données.

Solution A.

Sera un cauchemar de maintenance si vous devez ajouter de nouveaux produits

A1. Définir un tableau séparé pour chacune des catégories

Cars(CarID, ProductID, ..) Pets(PetID, ProductID, ..)

A2. Joignez les tables en fonction des relations afin d'utiliser les données

SELECT <fields> FROM Cars INNER JOIN Products ON Cars.ProductID = Products.ProductID

Solution B.

Cauchemar de maintenance pour différents types de propriétés (c'est-à-dire int, varchar, etc.)

B1. Définir une table pour les propriétés

CategoryProperty (CPID, Name, Type)

B2. Définir une table pour contenir les associations entre les catégories et les propriétés

PropertyAssociation (CPID, PropertyID)

B12. Définir une table pour contenir les propriétés (Alternative pour B1 et B2)

Properties(CategoryID, PropertyID, Name, Type)

B3. Pour chaque type de propriété (int, double, varchar, etc.) ajoutez une table de valeurs

PropertyValueInt(ProductID, CPID, PropertyID, Value) - pour int PropertyValueString(ProductID, CPID, PropertyID, Value) - pour les chaînes PropertyValueMoney(ProductID, CPID, PropertyID, Value) - pour de l'argent

B4. Joignez toutes les tables pour récupérer la propriété souhaitée.

En utilisant cette approche, vous ne devrez pas gérer toutes les propriétés dans une table distincte, mais leurs types de valeur. Fondamentalement, toutes les tables impliquées seront des tables de consultation. L'inconvénient est que, pour récupérer chaque valeur, vous devez & "Casse &"; pour chaque type de valeur.

Prenez en compte ces articles ( ici et ici ) lors du choix de l'une de ces approches. Ce billet de forum est également intéressant et en quelque sorte lié au sujet, même bien qu’il s’agisse de localisation.

Vous pouvez également utiliser Répondez avec Tomalak et ajoutez des caractères dactylographiés puissants si vous en ressentez le besoin.

J'ai récemment eu à le faire et j'utilise NHibernate où j'ai trois entités

Option de catégorie de produit OptionCategory

Un produit a 1 * catégories

Un produit a 1 * option

Une option a 1 OptionCategory

une fois que cela est configuré, vous pouvez utiliser la mise en cache Nhibernate

A bientôt

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