ID or Object?

ID or Object?

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


phucphlq posted on Monday, July 10, 2006

I have a class: Employee. I have two case to design this class

 

First:

Class Employee : Csla.BusinessBase<Employee>

{

      private Guid _Id;

      priavte string _Name;

      private Guid _ManagerId;

}

 

Second:

Class Employee : Csla.BusinessBase<Employee>

{

private Guid _Id;

      priavte string _Name;

      private Employee _Manager;

}

How to do? Which is best?

msk replied on Monday, July 10, 2006

I think the answer is - "It depends ..."

If you need the behaviour implemented in your Emplyee_Manager class then sure load it when you load an employee and perhaps expose it as property of Employee.

If you may need to load the manager object later then just retrieve the id (as in your first example).  You can then have a GetManager function that retrieves the manager later when required. 

If you just want to know who the employees manager is then just retrive the name

If you might want to change the employees manager then perhaps have a NameValueList of manager names and ids. 

Tom Cooley replied on Monday, July 10, 2006

As msk wrote, it does depend. But let me suggest that if you do go with the second option, take a look at the Composite design pattern to see if this is what you need. Unless you need to provide a hierarchy of managers and their people, you probably don't need this, but I thought I'd point it out in case that is the sort of functionality you desire.

Tom

vargasbo replied on Tuesday, July 11, 2006

Yes, the behavior you're looking for will guide your object design... I personally like the object. Something you'll also want to consider is UI criteria, I always like to expose items I uses in UI as properties in my object, makes life really easy for me.

RockfordLhotka replied on Tuesday, July 11, 2006

It depends indeed Big Smile [:D]

You are describing two entirely different things as options - each of which has its purpose.

Option 1 - where you maintain the Id values for other objects, enables a form of "using" relationship. Given that key information you have the ability to access or navigate to another object - but those would almost certainly be other ROOT objects.

Option 2 - where you maintain an instance-level reference to another object, is a parent-child relationship - at least by default. Unless you take pains to prevent it, those object reference will (and in fact must) point to child objects - and the root object then assumes responsibiilty for their lifetimes and persistence.

Option 2a - where you maintain instance-level references to another object BUT MARK that instance field as NonSerializable and NotUndoable, is a variation on option 1. Personally I try to avoid this 2a option like the plague, because it is far too easy to get it wrong and far too hard to get it right. To REALLY do this well, you have to ONLY use the instance field from within a property, and that property should include code to do null checks on the field, and to instantiate the object on demand. It is akin to lazy loading, but worse, because you are typically "lazy loading" root objects and then caching the reference.

The complexity comes in that the referenced object is a root. Which means someone might edit/save it without your knowledge. Which means you could be left holding an old (invalid) object reference. Which means that you need to implement an observer pattern to ensure that all these old object references get updated. Ugh! Avoid it!

Option 2b - where you implement lazy loading of child objects. Again, this requires extra work and discipline - because that instance field should ONLY be accessed by a single property, and that property should include null checking code to trigger the lazy loading of the child object. But this does REQUIRE that the referenced object be a child object, and that the root assume responsibiilty for its lifetime and persistence.

This table might help:

Target obj Ref type Outcome
Root Id Using relationship
Root Reference AVOID! (requires observer pattern to do correctly)
Non-CSLA Id Using relationship
Non-CSLA Reference Containment/aggregation
Child Id AVOID! (you can't manage a child through its Id)
Child Id->Reference Enables lazy loading (use Id to get Reference, then own reference)
Child Reference Normal parent-child containment relationship
Read-only Id Using relationship (no caching)
Read-only Reference Using relationship (with caching)

cardasim replied on Wednesday, July 11, 2007

Thank you, Rocky!
You've just served me a good OOP lesson and the answer
to a concrete question in one of my current projects.

Copyright (c) Marimer LLC