Monday, January 16, 2012
Currently being in the process of developing a business application, I came across an issue that looked harmless, but turned out to be what the title elegantly :-P implies.
Being very proud of what I can achieve in no time with LS, I had my product manager testing the application, when she ask me the simple: “How can I change something and save it as a new object with a new name. “It’s not implemented yet, but I am getting my hands on it right now and you will have it in no time”. What a typical developer answer!
“No time” turned out to be a full workday of experimenting trying to find out the best and most generic way to implement Save As functionality. Having an object being copied to another was something I had already implemented but I worked fine only on originals. Fetching an object to the client, modifying it somehow and then trying to copy to a new one, discard the changes of the original object and save the copy…well it was not a piece of cake, rather a pastry shop.
Creating a new object in a different instance of the dataworkspace and trying to copy ended up in a threading hell, as my object was not a simple one but having many one to many and many to many relations and threading had to be made “safe” to ensure consistency. Even if could manage to do it for the type of object requested by my product manager, the solution would be specific to this object and generalization would be a project on its own, with doubtful result.
Having the original and the copy on the same screen and context, made almost impossible to find a general way to discard changes made to the original (or any of the related objects) before saving the dataworkspace.
The final solution was rather naive, but totally generic and “LightSwitch” with only one drawback that I will mention at the end.
My datasource was an SQL Server based one. So I created a new one called myDataSourceNameCopy from the same database and also named all the entities EntityNameCopy (much better that EntityName1 suggested by default from LS. Now I had a myDataSourceName.Customer (for example) instance on my Customer Details screen and a myDataSourceNameCopy.CustomerCopy property waiting to be instantiated upon “Save As” command by the user.
A small parenthesis: one of the first contracts I designed and implemented for all the objects need was ICopyTo<TEntityType> where TEntityType : IEntityObject, which exposes a void CopyTo(TEntityType target). So Customer was already implementing ICopyTo<Customer> and what I had to do was implement ICopyTo<CustomerCopy> (and all referenced objects accordingly of course).
In order to by able to save from my screen both in myDataSourceName and myDataSourceNameCopy Ι took a look at this video tutorial. In the end when the used confirms the Save As, I save the changes in myDataSourceNameCopy, I discard the changes of myDataSourceName, close the screen, refresh the list of Customers (or whatever) and my “Saved As” Customer is there in the list of Customers ready to use. Well, I have to update two datasources every time my database changes but it’s a small price to pay, given that save as Is very important for my application.
The drawback is that I haven’t yet managed to figure out how this can be achieved with native LS datasources.
If anyone has implemented some other generic way to support Save As functionality and has to offer any ideas I would very much appreciate the comments.
2 comment(s) so far...
By Christian on
Thursday, January 19, 2012
You wrote: "Having an object being copied to another was something I had already implemented but I worked fine only on originals."
How did you achieve this? How can this done with relational data?
By Kostas Christodoulou on
Thursday, January 19, 2012
I am afraid I will dissapoint you. This done by code per case. As I wrote I have this ICopyTo interface implemented for all object types I need copy to and from. I write code doing the copy expicitly as when you have to copy a many to many relationship you will not copy the related objects where as in one to many you have to create also copies of the related objects for example.