There are two solutions, each having its merit and its drawbacks :
Option 1 : Genericity
a system wide option table, defined like this :
Create table tbGlobalOptions
(
OptionName Varchar(255) Identity,
OptionValue Varchar(255),
OptionType varchar(255)
isLocked bit --this indicated the value cannot be overridden by the user.
)
And an user options table :
Create table tbUserOptions
(
OptionName varchar(255)
UserID bigint,
OptionValue varchar(255),
Active bit
)
-- extra fields for logging omitted
-- keys omitted
The code contains an enum matching the OptionName column, so parsing Options from the code is trivial.
Cons :
- type safety can only be implemented using constraints or triggers (which is clearly harder to maintains than column types)
- it's harder to use the stored options directly from the database (as the parsing logic lives in the application code)
- retrieving all the options for a specific user is more costly (you cannot just select the user row)
Option 2 : Specialization (and strong typing)
A strongly typed option table containing one column per option
Create table tbOptions
(
UserId bigint, -- 0 for global defaults
Option1 int,
Option2 varchar(max)
Option3 int,
...
Option426 bit
)
Type safety is clearly a good thing, but here it has a huge cost :
- adding a new option requires a schema change
- the stored procedures used to update the table will contain a lot of duplicated code, as the logic (eg the isLocked mechanism, or some extra logging you might want to add) must be repeated over and over for each field. This is how you end up with stored procedures containing 1500 arguments.
- This solution doesn't scale well, as a table cannot have an unlimited number of columns (see max values for SQL Server 2008 here for example).
If you have 5 options and if this number is likely to stay the same over time, the second solution has its merits.
If on the other hand you plan to end up with thousands of options, this sound like a no-brainer for me : go for genericity !
In your application code, your problem is quite easily solved using a generic method :
OptionEntity<T> GetOptions<T>(string OptionName, T defaultvalue);
Edit to answer Bryan's comment below :
And yes, if there are 10000 values to store, there will be 10000 columns. That is true for every single table you will ever write. There is nothing special about an option table. Nothing.
This all depends on the level of abstraction we chose. How would you store a chess board position for example? You can clearly use a 64 columns table (64 values -> 64 columns)
or you can use a design with 4 columns only (game id, x, y, contents). Don't you think both can be adequate depending on the situation?
In this specific case, if options can be created on the fly, or if their numbers is expected to grow exponentially, those options are, to a certain extent, just another type of data. And you don't want to store data in your schema, do you?