In developing a shopping cart application I\'ve found that I needed to save settings and configurations based on the administrator\'s preferences and requirements. This info
As you guessed, and except for the simplest situations, putting all configurations parameters in a single rows has many drawbacks. It is a bad idea...
A convenient way to store configuration and/or user preference type of information is in XML. Many DBMSes support the XML data type. The XML syntax allows you to expend the "language" and structure describing the configuration as this configuration evolves. One advantage of XML is its implicit support for hierarchical structure, allowing for example to store small lists of configuration parameters without having to name these with a numbered suffix. A possible drawback of XML format is that searching and generally modifying this data isn't as straight forward as other approaches (nothing complicated, but not as simple/natural)
If you want to remain closer to relational model, the Entity-Attribute-Value model is probably what you need, whereby the individual values are stored in a table that typically looks like:
EntityId (foreign key to the "owner" of this attribute)
AttributeId (foreign key to the "metadata" table where the attribute is defined)
StringValue (it is often convenient to have different columns of different types
IntValue allowing to store the various attributes in a format that befits
them)
Whereby the AttributeId is a foreign key to a table where each possible Attribute ("configuration parameter" in your case) is defined, with say
AttributeId (Primary Key)
Name
AttributeType (some code S = string, I = Int etc.)
Required (some boolean indicating that this is required)
Some_other_fields (for example to define in which order these attributes get displayed etc...)
Finally the EntityId allows you to identify some entity which "owns" these various attributes. In your case it could be a UserId or even just implicit if you only have one configuration to manage.
Aside from allowing the list of possible configuration parameters to grow as the application evolves, the EAV model places the "meta data", i.e. the data pertaining to the Attribute themselves, in datatables, hence avoiding all the hard-coding of column names commonly seen when the configuration parameters are stored in a single row.
I have done this two ways in the past - a single row table and a key/value pair table - and there are positives and negatives to each approach.
The single row option is by far the easiest one to work with. This is because you can store each setting in its correct type in the database and not have to store the types of the settings as well as their lookup keys in code.
One thing I was concerned with using this approach was having multiple rows in the "special" single row settings table. I overcame this by (in SQL Server):
This means that only one row can exist in the table because the bit column has to have a value of 0, but there can only be one row with that value because of the unique constraint.
I'm not sure a single row is the best implementation for configuration. You might be better off having a row per configuration item with two columns (configName, configValue), although this will require casting all of your values to strings and back.
Regardless, there's no harm in using a single row for global config. The other options for storing it in the DB (global variables) are worse. You could control it by inserting your first configuration row, then disabling inserts on the table to prevent multiple rows.
You certainly don't have to change your schema when adding a new configuration parameter in the normalized approach, but you're still probably changing your code to process the new value.
Adding an "alter table" to your deployment doesn't seem like that big of a tradeoff for the simplicity and type safety of the single row approach.
A common way to do this is to have a "properties" table simmular to a properties file. Here you can store all your app constants, or not so constant things that you just need to have around.
You can then grab the info from this table as you need it. Likewise, as you find you have some other setting to save, you can add it in. Here is an example:
property_entry_table
[id, scope, refId, propertyName, propertyValue, propertyType]
1, 0, 1, "COMPANY_INFO", "Acme Tools", "ADMIN"
2, 0, 1, "SHIPPING_ID", "12333484", "ADMIN"
3, 0, 1, "PAYPAL_KEY", "2143123412341", "ADMIN"
4, 0, 1, "PAYPAL_KEY", "123412341234123", "ADMIN"
5, 0, 1, "NOTIF_PREF", "ON", "ADMIN"
6, 0, 2, "NOTIF_PREF", "OFF", "ADMIN"
This way you can store the data you have, and the data that you will have next year and don't know about yet :) .
In this example, your scope and refId can be used for whatever you want on the back end. So if propertyType "ADMIN" has a scope 0 refId 2, you know what preference it is.
Property type comes in hand when, someday, you need to store non-admin info in here as well.
Note that you should not store cart data this way, or lookups for that matter. However if the data is System specific, then you can certainly use this method.
For example: If you want to store your DATABASE_VERSION, you'd use a table like this. That way, when you need to upgrade the app, you can check the properties table to see what version of your software the client has.
The point is you do not want to use this for things that pertain to the cart. Keep you business logic in well defined relational tables. The properties table is for system info only.
Personally, I would store it in a single row if that is what works. Overkill to store it in an SQL table? probably, but there is no real harm in doing so.