Wishlist: save without returning new object instance via managed properties

Wishlist: save without returning new object instance via managed properties

Old forum URL: forums.lhotka.net/forums/t/5863.aspx


Patrick posted on Monday, November 24, 2008

Hi,
 
considering that we now have new and great possibilities with the managed properties in CSLA 3.6 I was wondering what it would take to address this:
 
Currently whenever one calls the save method on a root object a new object instance is returned after the save. From my perspective this has several drawbacks:
•    It makes UI code more complex because all data bound object instances need to be swapped out
•    When working e.g. with a big node based view it means that all nodes need to be recreate after a save because the references are invalid which turns out be a costly operation
•    It has the potential to cause bugs as it can easily happen that we work by accident with an old object instance
•    etc.
For CSLA.NET objects which contain all their state in managed properties it seems that it would be possible to automatically refresh the managed properties after a save.
So the fields would change but not the business object itself. This in turn would mean that the object reference would remain valid.
It wouldn't work if managed properties aren't used but that could just be a requirement to be able to use this feature.
 
Here is another thread from 2006 discussing the same topic: http://forums.lhotka.net/forums/2/2757/ShowThread.aspx
 
Just wanted to throw it out there for discussion Smile [:)],
Thanks,
Patrick

DocJames replied on Monday, November 24, 2008

That would be a very cool feature! I don't know if it's possible though ...

At the moment I'm doing it on a child level - I only update the changed children og replace the returned objects in the original collection. Therefore I always reference the original collection in the UI.

Jimmy

Patrick replied on Wednesday, November 26, 2008

DocJames:
That would be a very cool feature! I don't know if it's possible though ...

Hi Jimmy,

it seems like if it was handled on the data portal level...
All saves go through the data portal and at some point in time the data portal has the old object and the new object side by side and then it could just invoke a method in the base class of the old object to refresh it's values from the new object.
Then instead of returning the new object the data portal would return the old object and dispose of the new one.
This would be transparent to the developer... At least that's what it seems :)
So I'm wondering if this be a workable solution Rocky?

Thanks,
Patrick

Ash002 replied on Wednesday, November 26, 2008

If the server is not altering the object, does the client need to use the result of the save? or can it hang onto the original object?

rsbaker0 replied on Thursday, November 27, 2008

Ash002:
If the server is not altering the object, does the client need to use the result of the save? or can it hang onto the original object?

Beginning with CSLA 3.0 or so the framework changed to save a clone of the object (first as more of an option, now it's more the default in 3.5 and later). So, the original object is still dirty even after the save is successful. Subsequent attempts to save it would probably produce an error similar to a concurrency violation (e.g. it would look like someone else had changed the object while you were working with it).

Also, if you are using EditableRootListBase, it replaces the original item with the returned object, so if you are holding your own pre-saved copy of the object somewhere, it is effectively orphaned or dead and subsequent changes to it won't be saved.

Patrick replied on Monday, December 01, 2008

Hi,

just bumping up the thread to see if there are any more thoughts about this (I consider it a very helpful feature for CSLA.NET):
Patrick:

Currently whenever one calls the save method on a root object a new object instance is returned after the save. From my perspective this has several drawbacks:
•    It makes UI code more complex because all data bound object instances need to be swapped out
•    When working e.g. with a big node based view it means that all nodes need to be recreate after a save because the references are invalid which turns out be a costly operation
•    It has the potential to cause bugs as it can easily happen that we work by accident with an old object instance
•    etc.
For CSLA.NET objects which contain all their state in managed properties it seems that it would be possible to automatically refresh the managed properties after a save.
So the fields would change but not the business object itself. This in turn would mean that the object reference would remain valid.
It wouldn't work if managed properties aren't used but that could just be a requirement to be able to use this feature.
Patrick:
it seems like if it was handled on the data portal level...
All saves go through the data portal and at some point in time the data portal has the old object and the new object side by side and then it could just invoke a method in the base class of the old object to refresh it's values from the new object.
Then instead of returning the new object the data portal would return the old object and dispose of the new one.
This would be transparent to the developer... At least that's what it seems :)
So I'm wondering if this be a workable solution Rocky?


Thank you very much,
Patrick

RockfordLhotka replied on Monday, December 01, 2008

This can be done, but would basically require abandoning the BinaryFormatter and NetDataContractSerializer.

I did abandon those for Silverlight, though not by choice, and my replacement serializer comes with some limitations.

It will be interesting to see, as people start using CSLA .NET for Silverlight, whether that becomes a problem for most people. If it doesn't seem to be a big issue for most people, it would be possible to alter CSLA to use a similar technique to do in-place updates of the object graph.

However, it is unlikely that such a change could be done in a totally backward compatible manner. Partially because changing the serializer would impose direct restrictions that will likely burn some people. And partially because some apps may assume objects are replaced, and re-using instances could have all sorts of interesting side-effects in terms of state management.

I suspect this is the kind of change that is more like a CSLA 1.x to 2.x change than a 2.1+ to 3.6. Less evolutionary and more revolutionary.

It is probably the kind of thing I'll do when I also abandon Windows Forms, asmx and other old technologies - and only if there's broad support for such a big thing.

Skafa replied on Tuesday, December 02, 2008

,,Partially because changing the serializer would impose direct restrictions that will likely burn some people.''

Just for clarity, what restrictions are you talking about?

Remco

RockfordLhotka replied on Tuesday, December 02, 2008

The BF and NDCS can serialize any Serializable object, and NDCS can also serialize any DataContract object.

 

The MobileFormatter (the one we wrote for Silverlight) can not handle those objects. Your object must implement IMobileObject, which is a little tricky. Or it must inherit from MobileObject, MobileList or one of the other base classes we created that do implement IMobileObject.

 

Also, if you use private backing fields, your object must override a couple methods to get/set your state during serialization/deserialization. If you use managed backing fields this is automatic.

 

So you can see, that the very obvious restrictions are that all objects in your object graph must implement IMobileObject, and must either override those two methods and/or use the field manager to manage all field values in the object.

 

The primary reason for this is that Silverlight doesn’t have the reflection necessary to implement a “real” serializer (see my blog for much discussion). However, the same techniques we used to avoid reflection are also the basic techniques you’d use to do in-place serialization/deserialization of object state.

 

Rocky

Patrick replied on Tuesday, December 02, 2008

RockfordLhotka:
This can be done, but would basically require abandoning the BinaryFormatter and NetDataContractSerializer.
I'm just trying to understand why it would need to abandon anything? Below is a very simplified example but wouldn't it go in the right direction without needing to change serialization etc.?

[Serializable()]
public abstract class CfxBusinessBase<T> : global::Csla.BusinessBase<T> where T : CfxBusinessBase<T>
{
    /// <summary>
    ///  DataPortal Methods
    /// </summary>
    /// <param name="newBO"></param>
    /// After getting a new object call
    /// objectToReturn = ManageObjectStateChange(objectToReturn);

    protected bool KeepObjectStateBetweenDataPortalCalls { get; set; }
    internal virtual T ManageObjectStateChange(T newBO)
    {
        if (KeepObjectStateBetweenDataPortalCalls)
            return MergeState(newBO);
        else
            return newBO;
    }

    /// <summary>
    /// Merges the state a new object with the current object to keep references
    /// If manged properties aren't used it would need to be overriden
    /// in an inheriting class to correctly map the properties
    /// (or the DataMapper could be used?)
    /// </summary>
    /// <param name="newBO">The new BO.</param>
    /// <returns></returns>
    protected virtual T MergeState(T newBO)
    {
        foreach (Csla.Core.IPropertyInfo iPropertyInfo in newBO.FieldManager.GetRegisteredProperties())
        {
            this.SetProperty(iPropertyInfo, newBO.GetProperty(iPropertyInfo));

            // Could be extended to go through IEditableBusinessObject
            // and IEditableCollection and call ManageObjectStateChange on them.
            // It would need to check for the correct primary keys and if it's
            // not found add the object as a new object to the IEditableCollection
        }
        return (T) this;
    }
}

Thanks,
Patrick

Patrick replied on Wednesday, December 03, 2008

Hi,

looks like the thread got hijacked Wink [;)].... I'm still wondering about the original question though:

Patrick:
RockfordLhotka:
This can be done, but would basically require abandoning the BinaryFormatter and NetDataContractSerializer.
I'm just trying to understand why it would need to abandon anything? Below is a very simplified example but wouldn't it go in the right direction without needing to change serialization etc.?

[Serializable()]
public abstract class CfxBusinessBase<T> : global::Csla.BusinessBase<T> where T : CfxBusinessBase<T>
{
    /// <summary>
    ///  DataPortal Methods
    /// </summary>
    /// <param name="newBO"></param>
    /// After getting a new object call
    /// objectToReturn = ManageObjectStateChange(objectToReturn);

    protected bool KeepObjectStateBetweenDataPortalCalls { get; set; }
    internal virtual T ManageObjectStateChange(T newBO)
    {
        if (KeepObjectStateBetweenDataPortalCalls)
            return MergeState(newBO);
        else
            return newBO;
    }

    /// <summary>
    /// Merges the state a new object with the current object to keep references
    /// If manged properties aren't used it would need to be overriden
    /// in an inheriting class to correctly map the properties
    /// (or the DataMapper could be used?)
    /// </summary>
    /// <param name="newBO">The new BO.</param>
    /// <returns></returns>
    protected virtual T MergeState(T newBO)
    {
        foreach (Csla.Core.IPropertyInfo iPropertyInfo in newBO.FieldManager.GetRegisteredProperties())
        {
            this.SetProperty(iPropertyInfo, newBO.GetProperty(iPropertyInfo));

            // Could be extended to go through IEditableBusinessObject
            // and IEditableCollection and call ManageObjectStateChange on them.
            // It would need to check for the correct primary keys and if it's
            // not found add the object as a new object to the IEditableCollection
        }
        return (T) this;
    }
}
Thanks,
Patrick

RockfordLhotka replied on Wednesday, December 03, 2008

Patrick,

 

Your idea works in the simple case, and maybe in more complex cases, though maybe not.

 

Consider that it has to work at the object graph level. So it has to work with a parent-child-grandchild scenario, where there are possible cross-links between some of the objects in the graph. And it has to work in the case where an object was deleted from a list, and so the graph returned from the server won’t have a value corresponding to an object that the client does have in memory.

 

I’m not saying it can’t be done. I’m saying that it appears simple for an object, but in reality it is quite complex to do for an object graph.

 

Also consider that your existing objects have code in OnDeserialized() (and so does CSLA itself) – none of which would be good to run in this new model. While the entire object graph would come back from the server, you really don’t want those objects to do anything because you are going to copy the data out of them and discard them.

 

There are a lot of assumptions in CSLA, and I suspect in business objects, where actions are triggered on deserialization of objects from the server. All those assumptions would become wrong, and all that behavior would need to be suppressed or moved to some new trigger condition.

 

Finally, there are performance considerations. The copy of data from the returned object to the original object must be done at the field level. To do this in a general way requires reflection. If the objects moving over the wire were DTOs, at least they’d have public field data, which makes the reflection cheaper. And when combined with the field manager you can avoid reflection – which is what the MobileFormatter does for Silverlight.

 

 

What I’m saying is two things. First, this is a very non-trivial idea. Second, the efficient way to do this is to separate the object state from the object instance. This is what MobileFormatter does, and what BinaryFormatter/NDCS do not. So from an efficiency perspective, MF is arguably a better model – and it is certainly better for the type of solution we’re discussing here.

 

So then I’m left with a choice (assuming I do this at all) of doing it in a way that (I think) misuses the BF/NDCS, or of doing it the “right way” by decoupling the state from the object.

 

Also, I am looking to the future of Silverlight and Azure (and partially trusted web hosting and maybe even .NET CF), where MobileFormatter works, and BF/NDCS do not. In that future you could envision CSLA abandoning BF/NDCS entirely. That’s a big step – and not something I’d do casually – but it is a consideration.

 

Rocky

Patrick replied on Wednesday, December 03, 2008

Thank you very much Rocky. I appreciate you taking the time to answer.
RockfordLhotka:
the efficient way to do this is to separate the object state from the object instance. This is what MobileFormatter does, and what BinaryFormatter/NDCS do not......So then I’m left with a choice (assuming I do this at all) of doing it in a way that (I think) misuses the BF/NDCS, or of doing it the “right way” by decoupling the state from the object.
I agree and understand that it's a longer process to do it the correct way...
Would be good though if "decoupling the state from the object" could make it onto the wish list for a future version as I think there is a lot of benefit in it.

If me or anyone comes up with a "hack" of making it work in the short term even in limit scenarios I would appreciate if we could post the solution / approach here.

Thanks,
Patrick

RockfordLhotka replied on Wednesday, December 03, 2008

I just want to make sure we all understand the complexity here. This is a big version change (3.6 to 4.0 or something) because it would effectively break many things – including CslaDataSource, CslaDataProvider, CslaActionExtender and a whole slew of lower-level things. It would fundamentally change the way a lot of UI code works, along with some business object code.

 

In other words, this is a breaking change along the line of the 2.0 to 2.1 shift (at a minimum).

 

And I know the reply is “it could be optional” – but this means I’d have to make CslaDataSource, CslaDataProvider, etc. all work with both models. That’s probably not realistic to do that, and to maintain both models over time. It is already really time-intensive to test the UI related elements because you can’t automate or mock data binding in all 4 UI technologies (soon to be 5 with MVC).

 

So I see this as an all-or-nothing change. And so it is a change that will impact everyone using CSLA now.

 

Rocky

lukky replied on Tuesday, December 02, 2008

RockfordLhotka:

It is probably the kind of thing I'll do when I also abandon Windows Forms, asmx and other old technologies - and only if there's broad support for such a big thing.



Rocky,

Are you saying Windows Forms is an old technology and that you're going to remove support for it from CSLA.NET ? I really don't understand this. I was under the impression that Windows Forms was still going to be around for at least another 5 years.

Are we supposed to change technologies every 5 years or so ? If I move to WPF today, am I going to have to move again in 5 years ?

Please reassure me.

ajj3085 replied on Tuesday, December 02, 2008

Well, I don't know that there's any date for WinForms support to be dropped.

Oh, and yes, you will change UI technology every five years or so.  Hence why we use Csla.. so that we only have to re-write the UI or data access technology... but the business rules live on!  Wink [;)]

RockfordLhotka replied on Tuesday, December 02, 2008

>Oh, and yes, you will change UI technology every five years or so. 

>Hence why we use Csla.. so that we only have to re-write the UI or

>data access technology... but the business rules live on!

 

Exactly! My comment was somewhat tongue-in-cheek, but is also only funny because it is so sadly true…

 

Windows Forms may well be around for another 5 years. Probably more like 10 really, as technologies die slowly. But remember, Windows Forms is already 7 years old, and no technology remains really mainstream for more than about 10.

 

But let’s face it, in five years Windows Forms will clearly be a legacy technology. Already we know it is a legacy technology – it is just one that is still widely used. But five years from now it will be both legacy and generally undesirable.

 

My comment regarding CSLA is half serious. Today there is one difference between Windows Forms and XAML that requires a config switch (to control how PropertyChanged works). Over time I rather expect that to get worse, as Windows Forms remains pretty constant and XAML rapidly evolves. I hope I’m wrong, and that they maintain a large amount of functional parity, but I expect that won’t be the case.

 

So at some point I’ll probably be left with a tough choice of either maintaining a “CSLA .NET for Windows Forms” and “CSLA .NET for Everything-Else” or of dropping Windows Forms support.

 

When will that occur? Or will it occur? I can’t say. Certainly it doesn’t seem like it will happen in .NET 4.0, though it is too early to tell for sure.

 

I guess what I’m getting at, is that you should panic or worry for the short term. But if you aren’t considering a migration strategy to XAML in your 5 year IT planning, it is probably time to start.

 

Rocky

 

 

tetranz replied on Tuesday, December 02, 2008

RockfordLhotka:
I guess what I’m getting at, is that you should panic or worry for the short term.
I'll set some time aside for that tomorrow. Smile [:)]

RockfordLhotka replied on Tuesday, December 02, 2008

>you should panic or worry for the short term

 

You SHOULDN’T panic…

 

Geez, fat fingers today…

 

Rocky

lukky replied on Tuesday, December 02, 2008

RockfordLhotka:
I guess what I’m getting at, is that you *shouldn't* panic or worry for the short term. But if you aren’t considering a migration strategy to XAML in your 5 year IT planning, it is probably time to start.

 Rocky

Well, of course I do expect technologies to evolve and eventually decay, but I really wasn't under the impression that WinForms was already at that stage.

As for moving towards XAML, I appreciate your suggestion as it makes me realize that I can't sit on it for too long. I guess my general perception of WPF is that it is still lacking the rich "out of the box" experience that we got from .NET 2.0. By that I mean the fullness of the Controls toolbox. For all I know, there is still not a DataGrid with the possibilities of the Windows Forms' one. Am I wrong ?

Anyway, thank for reassuring me that support for WinForms is not about to disappear from CSLA in the near future.


RockfordLhotka replied on Wednesday, December 03, 2008

I did add this to the wish list: http://www.lhotka.net/cslabugs/edit_bug.aspx?id=248

Patrick replied on Wednesday, December 03, 2008

RockfordLhotka:
I did add this to the wish list: http://www.lhotka.net/cslabugs/edit_bug.aspx?id=248
Thanks,
Patrick

Copyright (c) Marimer LLC