views:

79

answers:

3

I'm having an internal debate about where I should handle checking for changes to data and can't decide on the practice that makes the most sense:

  1. Handling IsChanged in the GUI - This requires persistence of data between page load and posting of data which is potentially a lot of bandwidth/page delivery overhead. This isn't so bad in a win forms application, but in a website, this could start having a major financial impact for bandwidth costs.
  2. Handling it in the DAL - This requires multiple calls to the database to check if any data has changed prior to saving it. This potentially means an extra needless call to the database potentially causing scalability issues by needless database queries.
  3. Handling it in a Save() stored proc - This would require the stored proc to potentially make an extra needless call to the table to check, but would save the extra call from the DAL to the database. This could potentially scale better than having the DAL handle it, but my gut says this can be done better.
  4. Handling it in a trigger - This would require using a trigger (which I'm emotionally averse to, I tend to avoid triggers except where absolutely necessary).
  5. Don't handle IsChanged functionality at all - It not only becomes hard to handle the "LastUpdated" date, but saving data unnecessarily to the database seems like a bad practice for scalability in itself.

So each approach has its drawbacks and I'm at a loss as to which is the best of this bad bunch. Does anyone have any more scalable ideas for handling data persistence for the specific purpose of seeing if anything has changed?

Architecture: SQL Server 2005, ASP.NET MVC, IIS7, High scalability requirements for non-specific global audience.

+2  A: 

I handle it in the DAL - it has the original values in it so no need to go to the database.

Otávio Décio
Depending on the design/implementation of the DAL, the values might not be kept, yea?
o.k.w
I thought about that, but the DAL doesn't have the original values at Post time without loading them from the database. The business object to be saved would be loaded from the Post data.
BobTheBuilder
That's why I made my DAL keep the original values - that's my design, it is correct that others might decide not to do it this way but for me it paid off over and over again.
Otávio Décio
@ocdecio, you have a very good point there. +1
o.k.w
@ocdecio - Can you elaborate on where the original data is stored? i.e. is your DAL maintaining a cache or is it loading up some original data cache into your business object?
BobTheBuilder
So you are basically saying number 2 out of the list of options is the best?
John MacIntyre
For web apps, the value objects that I am interested in are kept in the session. For desktop apps it is easier, as long as they are in scope I have them. When I submit a change, they are applied to the value objects, and my DAL compares the original values with the current values and then issues the correct update statement for those.
Otávio Décio
@ocdecio - So option 1. Not GUI per se, but in one of the storage mechanisms available at that layer. Is that right? Should your DAL know about session state? </sincerity intended>
John MacIntyre
The DAL doesn't know if its value objects are maintained in a session or not; as long as they are in scope they have the state at the time it was retrieved. Since they are just value objects they can be freely sent up and down the layers, including the GUI if necessary. Any changes made to them can be then inspected and the repository updated accordingly by the DAL.
Otávio Décio
@ocdecio - I must be missing something; So the DAL has the compare method, but the GUI calls it and passes the data?
BobTheBuilder
@BobTheBuilder - the way I have it implemented, my value objects derive from Entity which has the compare method which is called by the DAL whenever I send the VO's to be persisted. The compare method uses reflection to compare every property and generates a diff which is sent to the update builder at the DAL.
Otávio Décio
@BobTheBuilder - all the GUI has to do is update the VO properties; this has the added bonus that if the GUI changes the value and later puts it back to the original value it won't be sent to the database.
Otávio Décio
A: 

For each entity in your system introduce additional Version field. With this field you will be able to check for changes at the database level.

Since you have a web application and usually scalability matters for web application, I would suggest you to avoid IsChanged logic at the UI level. LastUpdated date can be set at the database level during Save operation.

Vitaliy Liptchinsky
I tend to use the Version field for concurrency: In that it doesn't really handle "You've changed this record", rather it handles "this record has changed in the database since you loaded it."
BobTheBuilder
+2  A: 

Okay, here's another solution - I've not thought through all the repercussions, but it could work I think:

Think about the GetHashCode() comparison functionality:

At page load time, you calculate the hash code for your page data. You store the hashcode in the page data or viewstate/session if that's what you prefer.

At data post (postback) you calculate the hash code of the data that was posted and compare it to the original hash. If it's different, the user changed something and you can save it back to the database.

  • Pros
    • You don't have to store all your original data in the page load which cuts down on bandwidth/page delivery overhead.
    • You don't have to have your DAL do multiple calls to the database to determine if something's changed.
    • The record will only be updated in the database if something's changed and hence maintain your correct LastUpdated date.
  • Cons
    • You still have to load any original data from the database into your business object that wasn't stored in the "viewstate" that is necessary to save a valid record to your database.
    • Change of one field will change the hash, but you don't know which field unless you call the original data from the database to compare. On a side note, perhaps you don't need to. If you've gotta update any of the fields the timestamp changes and overwriting a field that hasn't changed for all intensive purposes doesn't have any effect.
    • You can't completely rule out the chance of collisions but they would be rare. This comes down to is the repercussion of a collision acceptable or not?
  • Either/Or
    • If you store the hash in the session, then that saves bandwidth, but increases server resources so you have a potential scalability issue in either case to consider.
  • Unknowns
    • Is the overhead of updating a single column and different than that of updating multiple/all columns in a record? I don't know what that performance overhead is.
BenAlabaster
Given that a hash code is 1/10^42 and that the data in this application isn't a matter of life or death, I would say that this is a reasonable solution.
BobTheBuilder
I accepted this answer because it actually seems like the most optimal solution. It keeps delivery overhead/bandwidth down to the minimum without resorting to saving unnecessary data in the session and prevents unnecessary updates in the database. Overall, this addresses scalability flaws in other solutions the best.
BobTheBuilder
@BobTheBuilder - Thanks for the feedback. I'd also like to hear other people's opinions on this approach as I'm thinking about using it in my next project and would like some insight to potential drawbacks.
BenAlabaster