views:

1067

answers:

6

I want to create a product catalog that allows for intricate details on each of the product types in the catalog. The product types have vastly different data associated with them; some with only generic data, some with a few extra fields of data, some with many fields that are specific to that product type. I need to easily add new product types to the system and respect their configuration, and I'd love tips on how to design the data model for these products as well as how to handle persistence and retrieval.

Some products will be very generic and I plan to use a common UI for editing those products. The products that have extensible configuration associated with them will get new views (and controllers) created for their editing. I expect all custom products to have their own model defined but to share a common base class. The base class would represent the generic product that has no custom fields.

Example products that need to be handled:

  1. Generic product
    • Description
  2. Light Bulb
    • Description
    • Type (with an enum of florescent, incandescent, halogen, led)
    • Wattage
    • Style (enum of flood, spot, etc.)
  3. Refrigerator
    • Description
    • Make
    • Model
    • Style (with an enum in the domain model)
    • Water Filter information
      • Part number
      • Description

I expect to use MEF for discovering what product types are available in the system. I plan to create assemblies that contain product type models, views, and controllers, drop those assemblies into the bin, and have the application discover the new product types, and show them in the navigation.

  1. Using SQL Server 2008, what would be the best way to store products of these various types, allowing for new types to be added without having to grow the database schema?

  2. When retrieving data from the database, what's the best way to translate these polymorphic entities into their correct domain models?


Updates and Clarifications

  1. To avoid the Inner Platform Effect, if there is a database table for every product type (to store the products of that type), then I still need a way to retrieve all products that spans product types. How would that be achieved?

  2. I talked with Nikhilk in more detail about his SharePoint reference. Specifically, he was talking about this: http://msdn.microsoft.com/en-us/library/ms998711.aspx. It actually seems pretty attractive. No need to parse XML; and there is some indexing that could be done allowing for simple and fast queries over the data. For instance, I could say "find all 75-watt light bulbs" by knowing that the first int column in the row is the wattage when the row represents a light bulb. Something (NHibernate?) in the app tier would define the mapping from the product type to the userdata schema.

  3. Voted down the schema that has the Property Table because this could lead to lots of rows per product. This could lead to index difficulties, plus all queries would have to essentially pivot the data.

A: 

Put as much of the shared anticipated structure in traditional normalized 3NF model, then augment with XML columns as appropriate.

I don't see MEF (or any other ORM) being able to do all this transparently.

Cade Roux
A: 

I think you need to go with a data model like --

Product Table

  • ProductId (PK)
  • ProductName
  • Details

Property Table

  • PropertyId (PK)
  • ProductId (FK)
  • ParentPropertyId (FK - Self referenced to categorize properties)
  • PropertyName
  • PropertyValue
  • PropertyValueTypeId

Property Value Lookup Table

  • PropertyValueLookupId (PK)
  • PropertyId (FK)
  • LookupValue

And then have a dynamic view based on this. You could use the PropertyValueTypeId coloumn to identify the type, using a convention, like (0- string, 1-integer, 2-float, 3-image etc) - But ultimately you can store everything untyped only. You could also use this column to select the control template to render the corresponding property to the user.

You can use the Value lookup table to keep lookups for a specific property (so that user can choose it from a list)

amazedsaint
A: 

I think you should avoid the Inner Platform Effect and actually build tables for your specialized entities. You'll be writing specific code to manage them so why not have proper backing tables too?

It will make your deployment slightly harder - drop in an assembly and run a script - but it will probably save you a lot of pain in the long run.

Andrew Kennan
+1  A: 

Use a Sharepoint-style UserData table, that has a set of string columns, a set of int columns, etc. and a Type column.

Then you have a list of types table that specifies the schema for each type - its properties, and the specific columns they map to in the UserData table.

With things like Azure and other utility computing storage you don't even need to define a table. Every store object is basically a dictionary.

NikhilK
A: 

Jeff,

we currently use a XML field in the Products table to handle all product-specific data. So our Products table has a few common fields that all products share, an XML which contains whatever a particular product needs additionally, and a few computed fields that grab into the XML and surface some of the frequently queried fields as "virtual" fields on the Products table (e.g. "Style" would be set to whatever the current product defines, or NULL, if the product doesn't have a Style property).

So far, we've been quite flexible with that approach - if you create some decent XSD schemas for your XML, you can even create C# proxy classes for these fields.

Works nicely for us - joining the best of both the relational and XML worlds.

Marc

marc_s
+1  A: 

Summarizing lets look at the options under consideration for storing product information: 1) some xml format in the database

2) similar to the post above about having x number of type defined columns (sharepoint approach)

3) via generic table with name and type definitions stored in lookup table and values in secondary table with columns id, propertyid, value (similar to #2 however this approach would provide unlimited property information

4) some hybrid of the above option where product table would have x common columns (for storage of properties common with all products) with y user defined columns (this could be m of integer type and n of varchar types). This may be taking the best of #2 and a normalzied structure as if you knew all the properties of all products. You would be getting the best sql performance for the properties that you use the most (probably those that are common across all products) while still allowing custom columns for specific properties with each product.

Are there other options? In my opinion I would consider 4 above as the best hybrid of the combinations.

  • dave
David