passing keys vs passing instances and the versioned business object problem

Published 03-30-2007 7:08 PM | jokiz

i once joined a team in developing a procurement/bidding system in ASP.NET.  it involved "project for bidding" creation, contractor's profile management (with lots of document uploads), and bid evaluation as the core functionalities.  contractors have the option to change any of its profile ranging from pcab license to bank certifications anytime.  one of the business rules was during bid evaluation, the profile of the contractor when he joined the project will be the ones to be evaluated.

this entails keeping a history of the profile of the contractors and tagging what version of it applies to a particular project he joined.  the design was to include an integer Version field to tables where it fits (all tables with both the ProjectId and ContractorId fields). 

to my surprise, classes are passing around ContractorId and VersionId as parameters.  passing around keys in the business layer is not OOP imo.  my usual design is coming from the UI, say selecting from a gridview, my codebehind gets the key from the gridview's datakeyscollection and i immediately construct the business object.  after i've constructed the business object, all logic or any processing that it will pass through will just be passing around this class instance.

being just another consultant hired to finish the project, you don't have the right and time to change all these existing and working codes (we don't have automated tests) so i basically lived with it.  could they have designed the classes to pass and receive Contractor instance instead, there would be minimal change in our code.

thinking about the same problem, i think i should have designed another Id (incremental identity) in the Contractor table (physical key), aside from the repeating ContractorId with its combination of VersionId.  Unique constraint will be on ContractorId and VersionId columns.  referencing tables will now use this Id field instead of the previous ContractorId field.

problem is, how do i generate the next ContractorId then with this design?  i can only think about using my nemesis = SELECT MAX(ContractorId) + 1.  Do you have any other resolutions for this, maybe let the database automatically generate this next ContractorId so i can eliminate this Select Max thingy which is prone for error?

Filed under: ,

Comments

# Comgen said on March 30, 2007 4:19 AM:

Master Jokiz, I have not tried this but i think adding a trigger for the table is another option

# amilr said on March 30, 2007 6:01 AM:

some other alternatives I've used for this:

1) generate a GUID for the ContractorId (easy way out :P)

2) normalize the ContractorId into another table where it will be the incremental Id

# jop said on March 30, 2007 7:58 PM:

My first option would be to use a dates (if necessary, datetime) instead of version IDs.

When contractors change, I log the date on when the change will be effective.

When looking for the contractor profile for a project, then I'll just use the a projects start date/bid date an look for the contractor "version" that was effective during that date.

# jop said on March 30, 2007 8:09 PM:

Read Temporal Objects from Martin Fowler's website (http://www.martinfowler.com/eaaDev/TemporalObject.html) for an object oriented solution for your problem.

In your scenario, a Contractor will be a temporal object. Projects can have many bidding contractors. The relationship is contained in another object, say ProjectBid, which knows a project a contractor and the date the contractor joined the project.

# Jon Limjap said on March 30, 2007 8:59 PM:

As amil pointed out, you could've just used sequential GUIDs. Some other ID/PK should then be used to indicate the linked profiles. Use the GUID to link that specific profile instance to the bid.

# jokiz said on April 14, 2007 6:29 PM:

thanks guys!