Design – Referencing Database Values in Business Logic

design

I guess this is another question about hard coding and best practices. Say I have a list of values, lets say fruit, stored in the database (it needs to be in the database as the table is used for other purposes such as SSRS reports), with an ID:

1 Apple 
2 Banana 
3 Grapes

I may present them to the user, he selects one, it gets stored in his profile as FavouriteFruit and the ID stored in his record in the database.

When it comes to business rules / domain logic, what are the recommendations for assigning logic to specific values. Say if the user has selected Grapes I want to perform some extra task, what's the best way to reference the Grapes value:

// Hard coded name
if (user.FavouriteFruit.Name == "Grapes")

// Hard coded ID
if (user.FavoriteFruit.ID == 3) // Grapes

// Duplicate the list of fruits in an enum
if (user.FavouriteFruit.ID == (int)Fruits.Grapes)

or something else?

Because of course the FavouriteFruit will be used throughout the application, the list may be added to, or edited.

Someone may decide that they want 'Grapes' renamed to 'Grape' and this would of course break the hardcoded string option.

The hardcoded ID isn't completely clear although, as shown you could just add a comment to quickly identify which item it is.

The enum option involves duplicating data from the database which seems wrong as it may get out of sync.

Anyway, thanks in advance for any comments or suggestions.

Best Answer

Avoid strings and magic constants at all costs. They are completely out of the question, they should not even be considered as options. This appears to leave you with only one viable option: identifiers, that is, enums. However, there is also one more option, which in my opinion is the best. Let's call this option "Preloaded Objects". With Preloaded Objects, you can do the following:

if( user.FavouriteFruit.ID == MyApplication.Grape.ID )

What has just happened here is that I have obviously loaded the entire row of Grape into memory, so I have its ID ready to use in comparisons. If you happen to be using Object-Relational Mapping (ORM), it looks even better:

if( user.FavouriteFruit == MyApplication.Grape )

(That's why I call it "Preloaded Objects".)

So, what I do is that during startup I load all of my "enumeration" tables (small tables like days of the week, months of the year, genders, etc.) into the main application domain class. I load them by name, because obviously, MyApplication.Grape must receive the row called "Grape", and I assert that each and every one of them is found. If not, we have a guaranteed run-time error during startup, which is the least malignant of all run-time errors.

Related Topic