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?
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.
It depends indeed
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) |
Copyright (c) Marimer LLC