简体   繁体   中英

Where to store business values in .NET - SQL Server applications

This has always been an chicken and egg problem among developers. Where do you store business values that are used within your application rules. (In either ASP.NET, Window Forms or any data-driven application)

I've seen people creating tables where they store text and value representation and then they link these records inside the code (by IDs or Text name). To me that's the worst possible way:

  • you have to maintain the table and create administration module for each
  • you have read the table every time you need to access business value
  • your application won't work without database being pre-filled -

And most developers tell me this the "best practice" which I'm not buying as it doesn't bring any benefit over approach where I place the business values directly to application like this:

public enum SourceLocation
        {
            Database = 0,
            File = 1,
            UserInput = 3        
        }

A then use integer on the [Column] coming from/to the database which directly casts to Enum on the data object so the logic can directly say:

if(DataObject.Column == SourceLocation.File)
       //Read From File

Which solves all the issues above but then when you run a report on the database outside of application you need to do the translation of these values in SQL.

So I'm still wondering whether there is another "better" solution or pattern that developers use. I mean every data-driven application must have an approach/design to this problem which has been around ever since the beginning.

I'm not quite sure I agree with you that storing these values in an enum provides you all that much benefit over storing them in some sort of an external data source.

you have to maintain the table and create administration module for each

True, storing values in an external datasource does add some architectural overhead. However, if you're using any sort of an ORM to handle your data access and code generation this is a pretty minor endeavor.

I'm not sure what you mean by "administration module" but I'm going to assume that you mean a repository and not some interface for users to manage the options themselves. I don't see why the latter would be required if the alternative is putting the values in an enum, since there's no way for users to manage those themselves either.

As far as "maintaining" the table goes, you don't really have to do any more maintenance than you would by adding or removing values from the enum. As JonH points out, the enum route requires that you rebuild and redeploy your entire application, rather than simply adding or removing rows from a datasource. To me, that is a greater maintenance burden.

you have read the table every time you need to access business value

Not true, since I'm assuming these values are fairly static it's pretty trivial to cache these values at application start up and be done with it.

your application won't work without database being pre-filled

So what? If the application is data driven, it's going to require that deploying and configuring the database is part of the deployment plan. Would adding 2 or 3 INSERT statements in a script add that much more complexity to the deployment process?

Which solves all the issues above but then when you run a report on the database outside of application you need to do the translation of these values in SQL.

Above all, this is the most compelling reason of all to store these values externally. Given the fact these values are being used in reports means that they have meaning outside the scope of your application . This means that when they are needed elsewhere, you will have to duplicate this knowledge every time. Any duplication in a system creates an additional maintenance burden and increases the chances for bugs to be introduced in future updates.

Finally, Enums tend to be more difficult in databinding to UI elements. When you can, they don't allow for "pretty" value names to be shown to the users. Instead they are shown dropdown boxes that contain items like "UserStoredFile" and "PickAndChooseAnotherEnumValue". Outside of associating the enum values to separate strings (more duplication, see the above paragraph), there is no way to overcome this limitation of Enums.

While it seems like no big deal, any decent developer should care about little details like this. Being concerned with the entire user experience is important. Chances are, if you're not particularly detail-oriented there are probably plenty of other places in your system outside of UI that will also have problems. Admittedly, this last point is more of a subjective soapbox type of argument :).

I would agree with you that storing these values only does not nearly justify adding a database to your application. However, you'll notice I usually say external datasource . There's no reason you can't set up your application to pull these values from XML, or some other type of external configuration file. However, if you've already got the database, you may as well keep it all in one place.

Edit:

Using these objects is pretty straightforward, they're just collections. They databind much more naturally than enums, and I imagine in data-driven applications that's important:

// Bind a collection of SourceLocation to an ASP.net dropdown list
ddlSourceLocations.Datasource = GetSourceLocations();
ddlSourceLocations.DataTextField = "LocationName";
ddlSourceLocations.DataValueField = "LocationId";
ddlSourceLocations.DataBind();

Of course, like you mention this is certainly not impossible with enums, its just typically not as nice.

Making these "business values" into full fledged objects over enums also allows you greater flexibility for the future, should the concept of a SourceLocation ever need to grow beyond a name and an ID.

Lets imagine that later an 'IsRemote' property is added to the SourceLocation, to denote that the location resides on a separate machine. SourceLocation now is able to accommodate rules that require this property:

if(myDataObject.SourceLocation.IsRemote) {
    // If the location is remote, do something extra   
}

You also would be able to filter down the collection of SourceLocation by this property, in case you had some code that required all locations where IsRemote is true:

var remoteLocations = GetSourceLocations().Where(x => x.IsRemote);

However, enums do have a distinct advantage over data-driven objects in one respect, and that is when they are used as application constants. In fact that is all an enum really is, a group of constants. It is more difficult to effectively write a rule against a static value when it is implemented as a dynamic, data-driven one.

In the case of your specific example this is true. All your rule is really saying is "If source location == 1, then do this." I would never want a bunch of magic ints floating around my application, so I would most certainly define an enum like the one you have above .

Does this mean that in this case I would use an enum only and forgo persisting the value in an external datasource? Not necessarily, it all depends on how the particular values are being used within the context of the system. In your example, theses values appear to have significance in the domain as a whole, not just a single application. You've described them as "business values" and mentioned that they are used in other applications such as reporting. To me, this would make it totally appropriate to provide a central location from which this knowledge can be shared, and I would persist them in addition to defining them in an enum.

You might say, "Wait.. isn't THAT duplication? Isn't that bad?" Well yes, but no less then you would have had using the enum-only route and you still gain the design bonuses of designing your business values as full-fledged domain objects.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM