I just ran into the exact situation AutoCloneOnUpdate was intended to prevent with business objects, except I was using a CommandBase object instead.
I executed a CommandBase-derived command that had a reference to a BusinessBase as a member, and an error occurred during the transaction. The transaction was rolled back, but unfortunately direct changes were made to the originally referenced BO that were reflected in the UI, when they should have been discarded. (This was over the local data portal). At first I thought I had major breakage in my transaction handling, but it turns out that CommandBase does not implement ICloneable, so no auto-cloning occurs.
This would be easy enough to fix by changing my intermediate CommandBase-derived class to implement ICloneable, but I'm just wondering if there is some reason I should not do this. (Or alternatively, is this something that should be built into CSLA)
I believe having CommandBase own a BusinessBase object is not valid state. A BusinessObject should only have one-1 parent (or owner).
If you were using any DataPortal except the LocalProxy - you would get a new instance of your BusinessObject in the CommandObject after execution and where would you put that object??
From my POW the CommandBase should encapsulate all its input/output as pure DTOs and not use BusinessBase object (or references to BusinnessObjects that are part of a business object structure).
Well, after any Save() operation on a BusinessBase, you also get a new instance of your BusinessObject and have to figure out where to put it. The problem is the same.
The parent of the BO is not the command, but whatever parent it had previously. I have used CommandBases in several cases to perform a server-side transformation using a BO as input. It works very well as long as you respect the same semantics as Save(), that existing client references to the BO must be replaced afterwards.
This particular use case was to create a new revision of the BusinessObject in the database and inactivate the old one. The entire object graph is duplicated into new records (same data, different keys), and active foreign key references to the object in the database are updated to refer to the new object rather than the old one, while closed references are not.
What I ended up seeing on the screen was that the original object was marked Inactive while the new one was not created -- not good.
Even if you weren't using BusinessBase here, you'd still have the issue if you had anything but value types in the Command -- you might end up with partially updated values in memory when a rollback occurs, but only if using the local data portal.
Quite the contrary, this technique is exactly how you would solve the "I have two Root objects which need to be saved under a single transaction" problem.
Probably what needs to be done though is that the BO is unbound from the form, cloned and ApplyEdit called. That should work... whether or not this should be handled by Csla though I'm not sure, although I would think it should (i.e., the Command and anything it contains should be cloned if the local dataportal is being used, for consistency).
Yes. I've used CommandBase objects for precisely this purpose also.
I implemented ICloneable in my CommandBase derived class, and CSLA handles it perfectly now. I was just wondering if this was either a deliberate omission from CSLA (e.g. there is a reason I should not do this), or otherwise maybe it should go on the list.
I copied the implementation right out of BusinessBase:
/// Creates a clone of the object.
/// A new object containing the exact data of the original object.
protected virtual object GetClone()
This is an oversight, command objects should auto-clone. I'll add this to the list for CSLA 4.
Copyright (c) Marimer LLC