Versioning Objects

Versioning Objects

Old forum URL: forums.lhotka.net/forums/t/7652.aspx


bkirkman posted on Friday, September 18, 2009

I have a project where whenever an EDIT takes place, the object and its children should be versioned. What I mean by "versioned" is a new unique identifier is created, inserting a new record and all the information is the same for the object except its version # is incremented and the PK is new.
I've looked into overriding the UPDATE method but am not sure how to change the PK of the object and return it. I am really doing an Insert instead of an Edit to the object.
Has anyone coded something like this before in CSLA?
TIA

ajj3085 replied on Friday, September 18, 2009

Interesting requirement. Probably what I would do is in the root object, override OnChildChanged and call MarkNew on the root, and then call an internal method SetNew on all its child objects (which would just cause the object to call its MarkNew).

Tom_W replied on Friday, September 18, 2009

You've no doubt got this well in hand, but just in case; I've done something like this in the past with versioning sales quotes (but not with CSLA) and the real pain point was making sure that anything that had a relationship to the record (i.e. PK/FK db relationship) stayed pointing at the right version. 

In our app there were records that had a FK relationship to the quote (which was the record getting versioned) and we wanted these relationships to point to the current version of the quote, not the historical one. 

After a lot of faffing it occured to us that it was better to keep the original version as the current record at all times and update it's version number, and to make a copy of the record with the new id which then became the historical audit record.  That way records with a FK to the quote didn't need to be updated too.

Obviously all of that depends on your particular UCs, I just mention it in case it saves you some of the pain we went through!

ajj3085 replied on Friday, September 18, 2009

Actually thta's what I've done too. When a user locks and then chooses to revise a quote, i copy the existing values to another table for history reasons, and then allow them to change the values on the "real" table.

Tom_W replied on Friday, September 18, 2009

The other solution I have used for this in the past is to have a 'stub' record that just contains say the QuoteId and the QuoteNo and then a QuoteRevs child collection that contains the actual data for each revision of the quote (i.e. Rev No and all of the actual quote contents such as values, descriptions etc).

That works well if you want 'live' access to the previous versions most of the time, but it's overkill if you only rarely want to see the previous versions and they aren't displayed on the main edit form say.

bkirkman replied on Friday, September 18, 2009

Tom,
Very interesting idea. So, If I understand this correctly you create a new object that is a duplicate of the existing one - inserting it with the current version, lets say "2", then "edit" the object and increment its version # so you are still working with the current record.
I do like this - everything is still in synch with the children and the actual insert is the "old" version of the object while the current one is the last edited version.
Is that correct?

Tom_W replied on Friday, September 18, 2009

Exactly so. 

You should be able to wrap the whole lot up in a transaction too to ensure the version numbers can't get messed up if there's a db write issue, although as I say I haven't done this in CSLA so I'm not sure exactly how you'd do that bit!

Incidentally, if you are writing the objects via stored procedures, it may be easier just to do the whole audit version creation there.  Normally I don't favour too much logic in sprocs, but in this case if you don't need the old version's data in the UI it may make more sense to shunt the work off to the db server and save sending essentially the same data twice across the network.  Also, if you make any modifications to the fields retrieved by the sproc you are probably more likely to remember to update the code that makes the copy of the object if it is in the same sproc.

EDIT:  Although if there are child collections that aren't written in the same sproc then that probably gets more tricky, in which case I would just make the copy in the business object.

ajj3085 replied on Friday, September 18, 2009

I have a sproc that copies to the history tables. That's probably the best way to go, as all the data stays within the database server's memory, instead of having to be read by an application only to be written to a different table. Regarding childs, I have other procs called by the main proc to handle copying of child data.

bkirkman replied on Friday, September 18, 2009

Tom and ajj,
I am going to go through the code now to see how to best update the children. I do prefer to do this through a stored proc but just have to analyze now how to handle this. Excellent ideas and I appreciate the assistance, Thank you.

david.wendelken replied on Friday, September 18, 2009

I've found the easiest way to do this is to approach things backwards. :)

Create "new" history data that stores the old values and relationships, then update data based upon the existing data to match the new values/relationships.

In other words, the object you just edited always, always, remains the latest version.  When it is changed, it creates prior versions.

It's much simpler.

 

Copyright (c) Marimer LLC