I've looked at the Diffgram sample and it looks good although complicated! Also you loose type information when you get to the server.
Is it not possible to hook into the serialization process when cloning the object for saving, to ignore the parts of the graph that are not dirty? After the Save, merge the subset graph back into the main graph.
If not, is it possible to create an alternative BinaryFormatter to do this.
This may be ridicuous but just thought I'd put it out there!
If you think about it, there are two different models here.
One is mobile objects, where your code on the client and server can assume that it always has access to the object graph. You can always look at other objects in the graph, run your business rules, and so forth. Generally speaking, you can perform most of the same operations on client or server and not worry too much about where the code is running.
The other is a model where the object graph only exists on the client. The server doesn't have the full object graph, so you can't assume that you can look at other objects in the graph, and you surely can't assume all your business rules can run (because they may rely on parts of the graph that aren't available).
I think it would be dangerous, and quite complex, to pull out parts of the object graph and send them to the server "intact". You'd end up, for example, with the server having an OrderEdit, LineItems and some LineItemEdit objects on the server. Suppose you accidentally triggered the business rule that recalculates the OrderTotal? It would only total the items that are on the server - and thus would create an invalid result - but one that seems perfectly valid given the objects available. Nasty!
In my view it is far safer, when using a diffgram/datagram technique, to have a different model for the data/objects sent to the server, so there's no chance of accidentally running logic that appears valid, but is actually invalid, which would almost certainly happen if you brought over just part of the actual object graph.
I agree fully, however.
If we could choose the model we wanted to use, either by decoration or configuration it would be awesome. I wonder how many developers dismiss Csla purely on the concept of mobile objects, we always think of the worst case scenario. We have a use case that lazy loads editable hierarchy, so in theory the user could happily click away loading the entire world into their graph from the client, click save and boom, major wait.
If this means BusinessRules require location information then that's ok.
I guess the main question was, Is it technically feasible the hook into Serialization or replace the formatter? Do you get to interact with what's being serialized? I was wondering if you had considered this in the past and dismissed it?
Well one of the main points of Csla is that it enables mobile objects. The design is there to support running business rules on a seperate physical layer than the data access while providing the same context in both locations. So I'd expect many more choose Csla for this feature than don't. The need for diff-grams appears to be an edge case.
Usually when people go down this route there's a simpler solution; its rare that a user actually needs all the data in the first place. There have been other threads where the issue is that there are 1000 child objects, and sending them back and forth is expensive. Of course, the user is likely not going to edit all 1000 rows at a time then save, so the problem is the implementation of the use case; its bringing back too much data. Giving the user only the data that is relevent is the solution in that case.
In other cases, it may be there's a lot of data that legitmately needs to be there. There are solutions to that; lazy loading, splitting up the use case such that you end up with mutiple root objects. Perhaps not all the data need be saved together to begin with.
To your specific problem, are you sure you really need to edit the ENTIRE hierarchy at once, or can you use readonly objects to show the user, and build another set of objects for editing a specific subtree? I would investigate that if I were implementing the use case.
Unfortunately I can't comment on hooking into the serialization process, but I wanted to comment on the diff-gram vs. mobile object concept.
Yes, I agree.
However in my specific case the user is mainly tinkering with a Bill Of Materials and the context (place in hierarchy) is key to this. Each node could have 1000s of children which are not edited but a grandchild is edited because of its place in the hierarchy. The 1000's + 1 are sent to the server which I understand and in majority of cases agree with. Maybe I do need a different design for this but I can't see what it would be.
I don't really want to argue about diffgram and mobile objects, I selected Csla and knew about this from the get go.
In an ideal world however, having the framework capable of swicthing models would suit everyone. Some have/want an application server that just writes objects to the database (simple rules for length/required etc) and run commands (re-fetching object server-side if neccessary).
I guess the point is that the server-side code is completely different in the mobile vs diffgram model.
In the mobile object model, the server-side code has access to the entire object graph. All four standard CSLA data access models are available.
In the diffgram model, the server-side code has access only to the changed data (and whatever other data you decide to send over the wire). So the actual business objects aren't there on the server at all, so you really can't think about the data access the same way.
Basically the diffgram model requires a separate command object to transport the diffgram itself to the server, and the data access code is associated with that command object, not the business object graph itself (because that graph never gets to the server). And of course an updated diffgram needs to flow back to the client so the real object graph can be updated with new primary keys, timestamps and so forth.
It is not possible to make this magically automatic.
Partially because hooking into BinaryFormatter/NDCS is non-trivial and would force you to write serialization code in every one of your business classes (a primary design goal when I started CSLA .NET was to avoid that sort of thing, since it was a major source of bugs in the VB6 world).
And partially because you have to write this command object, and you have to write the associated data access with full understanding of the shape of the diffgram. So that data access code is really quite different from "normal" data access code you'd find for regular CSLA objects.
And partially because any server-side business rules or business logic must also be written with full understanding of the diffgram - again, the real object graph isn't there, so such business logic is often more complex because it has to deal with an incomplete set of data and know how to work around that fact.
What I meant was the following:
In configuration client-side you configure the dataportal to use MagicBinaryFormatter. MagicBinaryFormatter is used instead of BinaryFormatter to do the serialization. This new formatter serializes the object graph in a way so that the stream only contains dirty objects in the graph, obviosuly including non-dirty parent objects.
This stream goes over to the server and is deserialized (either using the same MagicBinaryFormatter or the normal BinaryFormatter.) This would produce an object graph that is a subset of the master object graph but is the same type (at root level.)
This then goes through the portal Update as a normal and is saved. The subset object is sent back using the normal BinaryFormatter to the client and the client data portal merges the subset back with master object graph.
This is all using the standard object = object.Save().
Viola! All we need is a MagicBinaryFormatter and an ObjectGraphMerge!! Maybe server only rules, but I'm not really getting the server rules part of this discussion.
I understood that this is what you were proposing.
What I'm saying is that I don't think that's really workable. The server-side object graph would be incomplete, but would be using the same classes. So any business rules in your classes that might be triggered on the server would almost surely fail, because they wouldn't have the full object graph available.
Or worse, those rules would not fail, but would produce invalid results. For example, the rule that calculates the total amount due for the sales order would only calculate based on the dirty line items that exist on the server - so the order total would be incorrect as it would have ignored all the unchanged line items that exist only on the client.
So all of a sudden you need to make your rules aware of whether they are running with the full object graph, or in this bastardized partial-graph scenario. And I suspect the expectation would be that CSLA would somehow make that magically be a non-issue as well
I don't really know how the rules fire on the server. I'm using the ObjectFactory and not firing any rules in the Update method.
Just as a thought on how to get around this - rather than try to complicate the scenario to get around all the built in CSLA power why not just by-pass it directly which is what you are saying you want to do anyways?
I had the case where I had to do an auto-save in the background and the biggest issue was the lag over the internet so I had to just send the bare minimum. I had a parent, children, and some grandchildren. What I did was:
Added an IAutoSave interface to objects that matter
Collect a list of all my objects that needed updates.
Flagged them as autosave Start and a timestamp
dumped all those objects in to a command and sent that to the server
Server did the updates and stamped the records with the autosave timestamp and sent back success/fail
On success I processed all my flagged objects and updated their last update timestamp with the autosave timestamp
If the object had not been touched since the autosave started then I marked it as clean. If the user had touched it again while the background save was happening I left it as dirty.
The user then had an option to QuickSave (manual version of auto-save) or Save and exit. The save and exit was my full blown save where I pushed everything to the server. Most of my logic was replicated between the two saves anyways.
It seem to work very well (Silverlight Implementation). I wasn't running rules or mods on the server, just a simple DB update. Might not work in your scenario but if you send enough data to process any logic you need you should be okay. I did my first implemenation where I sent back some information as well and updated more than just the timestamp. Even that I did with just sending back the PKey and the new data to streamline what was sent.
Isn't that just the current Diffgram solution with a different wrapper?
In an ideal world (for certain object graphs) I would like to add an attribute to the root ObjectFactory to say use Diffgram then the BO developers don't have to worry about the compexilities of how it works. They just need to know that at the server they will get a subset of the object graph. In most cases (for me anyway) the graph is just generically traversed and sent to the database using a mapping.
I know it goes against the mobile objects concept but if it worked both ways its a win-win.
I was thinking of using an alternative WcfProxy to achieve the diffgram solution. What I was thinking was somehow hacking at the FieldManager's FieldData before it goes over the channel, as my BO's only use FieldManager. Is this possible do you think? Would there be any areas where I should take extra care? Any thoughts apart from whats already been said?
It seems the best place to do this, as I can then use a proxy factory to determine which proxy is used based on object type.
I think you are right - you'd need to create a custom proxy/host - or at least proxy - to make this work, so you can have it use your custom serialization implementation.
You'll also need to formalize some scheme by which you can identify objects - when the diffgram comes back from the server you need to merge it into the existing object graph, which means you need some algorithmic way to relate diffgram objects with business objects. In a general case that probably means returning to using something like GetIdValue() from the early days of CSLA .NET.
Copyright (c) Marimer LLC