views:

1222

answers:

8

Almost every programmer did it once in his life: setting some flag if a variable's value changed. There's always lots of properties and you want to keep track if something changed

  1. in any property
  2. in a specific property
  3. or in some set of properties

I'm interested in different ways to implement the "dirty-flag" functionality for the above situations, besides the standard object wide dirty flag being updated on each property change. There must be something better than putting "dirty = true" in each setter: it just looks ugly and is a tedious work.

+3  A: 

I would put changed() in each setter, i.e. call a private method instead of just changing a flag. The method may then set a flag or do whatever processing is needed, e.g. it could also notify any observers.

starblue
+6  A: 

For my DAO I keep a copy of the original values as retrieved from the database. When I send it to be updated, I simply compare the original values with the current. It costs a little in processing but it is a lot better than having a dirty flag per property.

EDIT to further justify not having a dirty flag: if the property returns to its original value, there is no way to reflect that, the dirty flag continues dirty because the original value was lost.

Otávio Décio
Why is it a lot better than having a dirty flag per property? You're keeping more data in memory. I'm not saying what you're doing is not better, but you haven't justified it.
Sam Meldrum
If you really think about it I am not necessarily keeping that much more data in memory because I don't need to carry a status flag per property. I don't need to worry about setting it back to "unchanged" if the value returns to the original one . Also dirty flag would NOT allow me to go back.
Otávio Décio
I'm doing the same thing with my DAOs. It's good to be confirmed!
MicSim
using a dirty flag: 1 object with {n} properties needs ONE flagusing the way you described: 1 object with {n} properties needs to keep track of the initial values of {n} properties. Seems like a substantial more amount of work with alot more variables being stored.
Allen
@Allen - I keep track of each and every property so I don't include properties that were changed and reverted in the update statements. It is not a lot of work or a lot of variables, it is a separate instance of the same object.
Otávio Décio
+3  A: 

If you are setting a "dirty" flag realize that you are keeping state. At some point you need to take an action based on that state, otherwise you wouldn't need to keep the flag. So the question then becomes: is there another way to trigger the needed action? Sending messages of some kind? Who consumes the "dirty" state and takes action, and is there a cleaner interface for that notification?

dwc
+5  A: 

I used to have a base Entity class, providing Dirty/Removed Logic.

When writing Entity-subclasses, you could do something like:

public string Name
{
    get { return name; }
    set { setValue("Name", value); }
}

This works fine, but has the 'ugly string' desease...

Today you can use Lambda Expressions to exclude the strings:

set {setValue(x => x.Name, value);}

Or, and I think that this is the best solution, you could use AOP:

http://www.postsharp.org/

This way, you can define actions by Attributes. You create an attribute and specify that when the user changes the associated property, the entity becomes dirty.

Additionally, you can keep a list of properties in your class (base Entity) which will remember the changed properties, and access that list from your AOP Code.

Bertvan
This sounds like the best method IMO
Allen
voting up for the AOP suggestion, but the initial "setValue" method makes me cringe :)
msulis
+4  A: 

I've created a class called DirtyValue<T> which has an original value and a current value. On its first use it sets both the original value and the current value. Successive calls only set the current value.

You can tell if it has changed by comparing the two, with a readonly bool property called IsDirty(). Using this technique you can also get access to the original value as well.

pezi_pink_squirrel
Are the properties of type DirtyValue<T> or do you just have fields of type DirtyValue<T> and then just expose Currentvalue through the property? Still seems like hard work - although nice that you're not having to set isDirty = true; all over the place
Sam Meldrum
Yes they are values not properties. I expose them through props if necessary. I want to make sure that regardless of how they are set (with a property or directly) that the dirty thing still works.
pezi_pink_squirrel
erm, fields I mean, not values! :)
pezi_pink_squirrel
More info: I actually have a DirtyState object which acts like a ASp.NET session object, you can just throw any dirty values at it with a key so you don't have to declare them up front. This happens to solve a problem in the game server I develop for very nicely.
pezi_pink_squirrel
So you're keeping your fields not as separate variables, but in some sort of attribute map?
MicSim
Not exactly, think ASP.NET session, key value pair of string(keylookup) and DirtyValue<T> (value). This is so I can pass it from "session" to "session" (in the game's horrible menu system context). This method, like the DAO one also means if it's changed then changed back, it won't show as dirty.
pezi_pink_squirrel
It still don't get it...
DR
+3  A: 

In some situations with a data writer task and an independent reader task, I've given each task an updateCount variable. The producer increments its count whenever it writes. Whenever the reader wakes up and finds its count less than the producer's count, it does an update with the current values. You need a little special handling for counter overflow, but this is pretty simple to implement.

I've successfully used this technique in simulations - where the producer is the physics loop and the reader is the 3d display.

AShelly
+1  A: 

An interesting alternative to the explicit dirty=true approach, although it is probably overkill for most situations and often not applicable, would be to use guard pages. Set the memory page as read-only (e.g. with VirtualProtect() on Windows) and catch the signal/exception when the program tries to write to the page. Make a record that the page has been modified, then change the protection flags of the page to writable and resume execution.

This is the technique usually employed by operating systems to determine whether a page needs to be written to the swap file before it is evicted from RAM.

flodin
A: 

You may want to look at overriding the gethashcode and equals methods of your domain objects and storing the original hashcodes in a hashtable by object key. Then create a process that takes an object, find its key in the hashtable and compares hash values.

  • If hash same, no change. (do not send to repository or database)
  • if hash different, object has changes. (update)
  • If key not found, object is new. (insert)
  • Not sure how to determine if object needs to be deleted other than process delete on request and not using hashcode tracking for them.

I have not tried this and a hashtable may not be the best way to track object keys/hash values. It would save mem by tracking only hash codes and keys only. I am not 100% sure, but I think some orm's may use this method in their data context/tracking objects.

There's a problem with this approach: "Hash same" doesn't always mean "no change", it could mean "change", but the hash values collided.
Chris W. Rea