It is often the case that a tree is best represented as a set of read-only objects, not editable objects. In other words, ROLB instead of BLB.
You can then have a set of Command objects that are used to perform operations on the read-only objects. The Command object can change the server-side data (in the database) and if that succeeds it can alter the client-side object graph (or at least coordinate the updates to the object graph - I'm not advocating breaking encapsulation).
As a brief example, suppose I have ListA and ListB. The UI allows the user to move items from one list to the other, and these changes are immediate (no 'Save' button - the move is auto-committed to the database). If you implement both lists as ROLB, their implementation is pretty easy, as is the UI.
When the user drops an item from B into A, the UI can invoke an AddFrom() command:
_listA.AddFrom(_listB, item);
or something like that. This AddFrom() method would invoke a Command object to do the actual work:
public void AddFrom(ListType list, ItemType item)
{
ItemMover.DoMove(this, list, item);
}
the Command object is ItemMover, and would look like this pseudocode:
[Serializable]
internal class ItemMover : CommandBase
{
// declare id key value properties here
public static void DoMove(
ListType fromList, ListType toList, ItemType item)
{
var cmd = new ItemMover {
FromListId = fromList.Id,
ToListId = toList.Id,
ItemId = item.Id };
DataPortal.Execute(cmd);
// we get here because the server update worked
fromList.RemoveMovedItem(item);
toList.AddMovedItem(item);
}
protected override void DataPortal_Execute()
{
// update database to reflect change by using
// the id key value properties
// throw exception if this can't be done
}
}
Note that this does require that you implement internal RemoveMovedItem() and AddMovedItem() methods on your read-only list class. These would look like this:
internal void RemoveMovedItem(ItemType item)
{
IsReadOnly = false;
try
{
this.Remove(item);
}
finally
{
IsReadOnly = true;
}
}
This technique means you don't break encapsulation on any object. It provides a model by which you can implement discrete methods on what would otherwise be read-only lists, and is often the best model for implementing things list selection lists, treeviews and so forth.