Lazy loading and applyedit

Lazy loading and applyedit

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


eloycm posted on Tuesday, October 09, 2007

hello
I hava a parent object that has some lazy loading "childs". I'm experiencing troubles with beginedit applyedit, i can't find a way to keep their editlevel value aligned, because they are in fact independent objects so independent calls to their apply edit will result in an error
thanks in advance for your help.

RockfordLhotka replied on Tuesday, October 09, 2007

When you do lazy loading you must bring the new child object's edit level up to the level of the parent that is creating it. For example:

Public ReadOnly Property MyChild() As Child
  Get
    If _myChild Is Nothing Then
      _myChild = Child.GetChild(...)
      For index As Integer = 1 To Me.EditLevel
        _myChild.BeginEdit()
      End If
    Return _myChild
  End Get
End Property

From this point forward the child's edit level should be automatically maintained by CSLA and you shouldn't have to worry about it.

rsbaker0 replied on Friday, October 12, 2007

RockfordLhotka:

When you do lazy loading you must bring the new child object's edit level up to the level of the parent that is creating it.

You could make argument that this a workaround and really doesn't reflect what is actually happening (at least in the way I understand it).

If I am at EditLevel 2 and lazily load a child at level 2, the reference to that child didn't exist at level 1. If you cancel edit on the parent, it will go back to edit level 1. Shouldn't the child reference be null at level 1 since it was null when BeginEdit was called at level 1?

RockfordLhotka replied on Friday, October 12, 2007

Not really a workaround. N-level undo expects (now requires) that the entire object graph be in sync. If you load a child object late, then you must bring it in sync with the rest of the graph.

 

If you cancel the parent, the lazy loaded child will actually go away btw. Look at the undo code in UndoableBase – there’s a check there to see if the prior value was null, and if it was, then any current value is removed.

 

Rocky

 

 

From: rsbaker0 [mailto:cslanet@lhotka.net]
Sent: Friday, October 12, 2007 3:12 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] Lazy loading and applyedit

 

RockfordLhotka:

When you do lazy loading you must bring the new child object's edit level up to the level of the parent that is creating it.

You could make argument that this a workaround and really doesn't reflect what is actually happening (at least in the way I understand it).

If I am at EditLevel 2 and lazily load a child at level 2, the reference to that child didn't exist at level 1. If you cancel edit on the parent, it will go back to edit level 1. Shouldn't the child reference be null at level 1 since it was null when BeginEdit was called at level 1?



ajj3085 replied on Monday, October 15, 2007

rsbaker0:
You could make argument that this a workaround and really doesn't reflect what is actually happening (at least in the way I understand it).

If I am at EditLevel 2 and lazily load a child at level 2, the reference to that child didn't exist at level 1. If you cancel edit on the parent, it will go back to edit level 1. Shouldn't the child reference be null at level 1 since it was null when BeginEdit was called at level 1?

Ok, well what would be the result if you loaded the list up front, no changes where made, but BeginEdit was called on the parent object twice?  The result would be exactly the same.. so I'm not sure I call that a work around.

rsbaker0 replied on Monday, October 15, 2007

Rocky claims that the child added in the middle will just "go away" when UndoChanges is called, so it's probably OK. 

I'd just prefer the framework had an official way for parents to "adopt" lazy children rather than make the parent be concerned about the details of the undo implementation. (e.g. OnChildLoaded(), etc... )

I'm also not sure how to make this work with the lazy instantiation capabilities of an object mapper like NHibernate or the Wilson ORMapper, but that's another subject.

 

RockfordLhotka replied on Monday, October 15, 2007

That may happen at some point. I’ve mentioned this before too – at some point I’d like to create a “child manager”. Like a build-in BLB basically. This would change the way you’d declare and use child objects in your code, but would allow me to do some nice things on your behalf.

 

As I say, I haven’t done this, but the concept is along this line (for lazy loading):

 

Public Class Parent

  Inherits BusinessBase(Of Parent)

 

  Public ReadOnly Property Child() As Child

    Get

      If Me.Children(“Child”).IsEmpty Then

        Me.Children.SetChild(“Child”, Child.GetChild(Me._id))

      End If

      Return CType(Me.Children(“Child”).Child, Child)

    End Get

  End Property

 

End Class

 

Such a child manager would integrate directly with the n-level undo functionality, and so would already know the edit level at which the child should be – so it could force the child to that edit level in the SetChild() method, and track previous values and so forth.

 

Additionally, this child manager could handle the Parent reference stuff, so your single child objects and your BLB’s would get that set automatically. And the event hooking/rehooking for ListChanged and PropertyChanged would become automatic as well.

 

Finally, and this is a bigger deal, I’ve considered creating a BusinessChildBase class. Just like BusinessBase<T>, except for a child object. The value of doing this is that (coupled with a child manager) I could further automate some of the behaviors, including abstracting data access to a large degree – automatically cascading Update(), Insert() and DeleteSelf() type calls down through the children.

 

Rocky

 

 

From: rsbaker0 [mailto:cslanet@lhotka.net]
Sent: Monday, October 15, 2007 8:06 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] Lazy loading and applyedit

 

Rocky claims that the child added in the middle will just "go away" when UndoChanges is called, so it's probably OK. 

I'd just prefer the framework had an official way for parents to "adopt" lazy children rather than make the parent be concerned about the details of the undo implementation. (e.g. OnChildLoaded(), etc... )

I'm also not sure how to make this work with the lazy instantiation capabilities of an object mapper like NHibernate or the Wilson ORMapper, but that's another subject.

 



rsbaker0 replied on Wednesday, October 17, 2007

So I have been experimenting with this more and have run into something else.

If I have found that calling AcceptChanges() on the parent will not call AcceptChanges on the children if the parent is still bound (which happens when the parent is in a list on the form), so when I attempt to save the entire list, the children are at edit level > parent after AcceptChanges is called.

The particular line of code is:

// it is a child object so cascade the call

if (!_bindingEdit)

((Core.IUndoableObject)value).AcceptChanges(this.EditLevel);

The save operation doesn't care about this, but CopyState() fails with an edit mismatch if you try to call BeginEdit() on the list again.

Any thoughts?

 

ajj3085 replied on Wednesday, October 17, 2007

Are you following the example from Csla 3.0.2?  You have to unbind your objects before you can save them.  See the PTracker example.

rsbaker0 replied on Wednesday, October 17, 2007

ajj3085:
Are you following the example from Csla 3.0.2?  You have to unbind your objects before you can save them.  See the PTracker example.

Unbinding the object won't correct the mismatched edit levels.

While the list of parent objects was bound to a grid on the form, the grid called BeginEdit/ApplyEdit on each parent as it was being edited, bumping up the edit level of the parent during the edit process. The parent may have lazily loaded children, which are being manually "bumped up" to match the edit level of the parent.

When the grid calls EndEdit, the parent edit level is reduced, but the lazily loaded children are not reduced. 

Unbinding after this has happened (before attempting to save) won't fix these already mismatched edit levels.

RockfordLhotka replied on Wednesday, October 17, 2007

I see what you are saying. That is an interesting problem.

 

Prior to CSLA 3.0 this would have “worked” because the IEditableObject.ApplyEdit call would have cascaded to child objects. Unfortunately that isn’t how data binding expects it to work, and if any of those child objects were bound too, then it all got messed up. So in CSLA 3.0 I changed it so those calls don’t cascade to child objects – matching what data binding expects to happen – but making your scenario difficult (at best).

 

I don’t know of any obvious answer. It seems that there are (generally) three options. Either lazy load the child _before_ the edit is started, or bring the child to EditLevel-1 (but only if the parent is bound – which it can’t detect), or manually call *Edit() on the child when the parent’s ApplyEdit()/CancelEdit() is called (which you can detect, but can’t know if it was called due to IEditableObject).

 

Unfortunately I don’t have time to research this in the near future, but I look forward to hearing anything you can figure out.

 

Rocky

 

 

From: rsbaker0 [mailto:cslanet@lhotka.net]
Sent: Wednesday, October 17, 2007 10:29 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: Lazy loading and applyedit

 

ajj3085:

Are you following the example from Csla 3.0.2?  You have to unbind your objects before you can save them.  See the PTracker example.

Unbinding the object won't correct the mismatched edit levels.

While the list of parent objects was bound to a grid on the form, the grid called BeginEdit/ApplyEdit on each parent as it was being edited, bumping up the edit level of the parent during the edit process. The parent may have lazily loaded children, which are being manually "bumped up" to match the edit level of the parent.

When the grid calls EndEdit, the parent edit level is reduced, but the lazily loaded children are not reduced. 

Unbinding after this has happened (before attempting to save) won't fix these already mismatched edit levels.



rsbaker0 replied on Wednesday, October 17, 2007

RockfordLhotka:

I see what you are saying. That is an interesting problem.

 Prior to CSLA 3.0 this would have “worked” because the IEditableObject.ApplyEdit call would have cascaded to child objects. ... 

 

Maybe I'm just missing something, but it seems like this should work. Here are a few more details.

 

The basic editing paradigm here is that I hand a business object to a form. Before doing any binding, I call BeginEdit() so that any changes can be cancelled. If the user presses OK, then you ApplyEdit() and the Save the object, otherwise you CancelEdit() and discard the changes.

 

So, everything loaded when the form loads is at EditLevel 1 at this point.

 

The form binds child-parent objects (child object which also is a parent), which may lazily load "grandchildren", to controls on the form. A grid control on the form in particular is what is giving me trouble, since it calls BeginEdit() as you enter each row and EndEdit() as you leave. The lazy grandchildren will be loaded and manually bumped up to EditLevel 2 during the edit. The grid calls EndEdit, and the child-parent object goes back to EditLevel 1 because ApplyEdit is called, but the grandchildren stay at

EditLevel 2.

 

If you try to save, it seems to work (bound or unbound, doesn't really matter at that point), but the object can't be edited again because the edit levels don't match. Subsequent CopyState() will throw an exception.

 

When lazy loading a child object, it is possible to know whether you are bound or not via BindingEdit, which might make it possible to make adjustments in the editing level you bump to, but it's not clear to me whether n-1 would only work for this case and might not work for deeper editing levels.

rsbaker0 replied on Wednesday, October 17, 2007

^^^^

OK, syncing the EditLevel up to n-1 when lazy loading a child instead of n when BindingEdit is true seems to work for this particular form. I'll have to do more testing with more complicated scenarios.

In any case, this has been very educational. I had to write a quick debugging interface that detects any mismatch in EditLevel regardless of how deep it is in the object hierarchy (as well as tracing of all the object and child edit levels), so I have some good tools for future problems.

RockfordLhotka replied on Wednesday, October 17, 2007

There’s a whole thread on this, and I discuss it in the 3.0 ebook.

 

The rule is that you cannot call BeginEdit(), CancelEdit() or ApplyEdit() on the object while the object is data bound in Windows Forms. If you do, it confuses Windows Forms data binding and ultimately leaves the object graph in an incorrect state.

 

Look at the PTWin code in 3.0.2 to see the correct binding model.

 

Rocky

 

From: rsbaker0 [mailto:cslanet@lhotka.net]
Sent: Wednesday, October 17, 2007 9:04 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: Lazy loading and applyedit

 

So I have been experimenting with this more and have run into something else.

If I have found that calling AcceptChanges() on the parent will not call AcceptChanges on the children if the parent is still bound (which happens when the parent is in a list on the form), so when I attempt to save the entire list, the children are at edit level > parent after AcceptChanges is called.

The particular line of code is:

// it is a child object so cascade the call

if (!_bindingEdit)

((Core.IUndoableObject)value).AcceptChanges(this.EditLevel);

The save operation doesn't care about this, but CopyState() fails with an edit mismatch if you try to call BeginEdit() on the list again.

Any thoughts?

 



sigmondzavion replied on Tuesday, August 25, 2009

I have tried this lazy-load technique, as suggested by Rocky - but with no success. It seems that I can't call BeginEdit() on a BLB that has been designated as a child (a child list).

So ... the question is ... How do I get the child list up to the proper EditLevel when lazy loading?

Any suggestions would be welcome. I have been wrestling with Data Binding & Lazy Loading for the past 2 days with little success.

BTW: I love this framework. This is the first significant snag I have encountered. I am using CSLA 3.0.5

RockfordLhotka replied on Tuesday, August 25, 2009

One suggestion, fwiw, is to upgrade to 3.5 or higher, where you can make
your child reference be a managed property and let CSLA .NET do the work for
you. Even if you are stuck on .NET 2.0, there's now the N2 project so you
can get 3.6.3 for .NET 2.0.

Rocky

-----Original Message-----
From: sigmondzavion [mailto:cslanet@lhotka.net]
Sent: Tuesday, August 25, 2009 3:14 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] Lazy loading and applyedit

I have tried this lazy-load technique, as suggested by Rocky - but with no
success. It seems that I can't call BeginEdit() on a BLB that has been
designated as a child (a child list).

So ... the question is ... How do I get the child list up to the proper
EditLevel when lazy loading?

Any suggestions would be welcome. I have been wrestling with Data Binding &
Lazy Loading for the past 2 days with little success.

BTW: I love this framework. This is the first significant snag I have
encountered. I am using CSLA 3.0.5

sigmondzavion replied on Thursday, August 27, 2009

Rocky:

Thank you, for the prompt reply. We want to upgrade. However, the timing is not good for us, at the moment.

In the meantime, I have added 1 constructor & 1 factory method to our Child List implementation as below:


private ChildList(DataReader dr, int parentEditLevel, bool parentBindingEdit)
{
Fetch(dr);
for (int i = parentBindingEdit ? 1 : 0; i &lt; parentEditLevel; i++)
BeginEdit(); // Bring 'this' to proper EditLevel
MarkAsChild(); // Last thing we do
}

internal static ChildList Get(DataReader dr, int parentEditLevel, bool parentBindingEdit)
{
return new ChildList(dr, parentEditLevel, parentBindingEdit);
}



The key here, is to make sure that "MarkAsChild()" is the last thing called in the constructor.
This allows us to call "BeginEdit()" ... which brings the EditLevel of the child list to its proper level.

Notice that we are also examining the parent's "BindingEdit" property (via parentBindingEdit) to help determine the child's designated EditLevel. This is because the parent may be bound and in the processes of editing.

Of course, the parent was modified to call the new ChildList factory method, when lazy loading.

With limited testing, this work-around has worked well for us (so far ;). I hope this may help someone else out there.

Codelines replied on Monday, August 01, 2011

I know that what I'm gonna say isn't a solution, but using proxies perhaps we can circumvent problems related to lazy loading. From the parent point of view, all objects are eager loaded, but into the proxy the inner object will be lazy loaded when any proxy method be called. Using a code generator, creating proxies for business objects would not be a heavy work and the use of proxies can bring other gains besides a circumvent for problems with lazy loading. Using proxies we have another option to do the lazy loading too. For example, having a big collection, we can bring the data from the database and store the object data in the child proxies leaving the inner objects instantiation and initialization to be done on demand. This would give a gain in performance. Using proxies, when the business object is saved, the only reference to be updated is that into the proxy even if the proxy is multireferenced. Using proxies makes easier to implement the pattern "one instance, multiple references" for the real business object if desired. 

AaronH replied on Thursday, July 14, 2011

Is this still the recommended way to handle synching the edit level of lazily loaded children with their parent?

Taken from a very old post:

Public ReadOnly Property MyChild() As Child
  Get
    If _myChild Is Nothing Then
      _myChild = Child.GetChild(...)
      For index As Integer = 1 To Me.EditLevel
        _myChild.BeginEdit()
      End If
    Return _myChild
  End Get
End Property

My case specifically is this (Silverlight):

I have 2 grids: grid 1 is bound to editable roots.  Selecting an editable root lazily loads it's children and displays them in grid 2.

The problem happens when you click an editable cell in grid 1.  What happens is that the root object enters edit mode (so now root is in EditLevel 1).

Then the children list comes back and is set via LoadProperty.  But because the children are set after the EditLevel has incremented, AcceptChanges throws an exception when navigating to the next root. 

Any thoughts!

 

AaronH replied on Friday, July 15, 2011

Just an update as I work through this.

Setting the children when they come back to the parent's edit level doesn't work.

What happens is that if the parent's (root) edit level is 1, the children are set to 1.  But if you edit one of the children, the edit level for that child is now = 2.  And of course, saving invokes AcceptChanges which again, throws the UndoException as the edit levels of the parent and edited child are out of sink.

Also, the following block of code taken from the Creating Business Objects eBook does not fix this problem.  It presents the same issue unfortunately:

        public static readonly PropertyInfo<AddressEditList> AddressesProperty = RegisterProperty<AddressEditList>(c => c.Addresses, RelationshipTypes.Child | RelationshipTypes.LazyLoad); 
        public AddressEditList Addresses 
        { 
            get 
            { 
                if (!FieldManager.FieldExists(AddressesProperty)) 
                { 
                    DataPortal.BeginFetch<AddressListCreator>((o, e) => 
                    { 
                        if (e.Error != null) 
                            throw e.Error; 
                        else Addresses = e.Object.Result; 
                    }); 
                    return null; } 
                else 
                { 
                    return GetProperty(AddressesProperty); 
                }
            } 
            private set 
            { 
                LoadProperty(AddressesProperty, value); 
                OnPropertyChanged(AddressesProperty); 
            } 
        }


 

AaronH replied on Friday, July 15, 2011

I was able to successfully get the lazy loading - edit level mismatch issue resolved.  I am a bit uneasy about haveing had to add this logic, as I'm not entirely sure of the ramifications of doing this.  But things seem to be working, so here's what I did (code in bold):

So basically this going to commit the changes first before assigning the lazily loaded is assigned to the parent object (not ideal, but it works).   

        public static readonly PropertyInfo<AddressEditList> AddressesProperty = RegisterProperty<AddressEditList>(c => c.Addresses, RelationshipTypes.Child | RelationshipTypes.LazyLoad); 
        public AddressEditList Addresses 
        { 
            get 
            { 
                if (!FieldManager.FieldExists(AddressesProperty)) 
                { 
                    DataPortal.BeginFetch<AddressListCreator>((o, e) => 
                    {
                        if (e.Error != null)
                            throw e.Error;
                        else
                        {
                            for (int i = 0; i < EditLevel; i++)
                                this.ApplyEdit();
                            Addresses = e.Object.Result;
                        }
                    }); 
                    return null; } 
                else 
                { 
                    return GetProperty(AddressesProperty); 
                }
            } 
            private set 
            { 
                LoadProperty(AddressesProperty, value); 
                OnPropertyChanged(AddressesProperty); 
            } 
        }


Also, I think I have identified a bug (or at least i'm unsure why this is happening).  





If you have a grid bound to the address list via ItemsSource="{Binding Parent.Addresses}", 
the addresses will not update the UI after lazy loading if you have the RelationshipTypes.Child and 
RelationshipTypes.LazyLoad specified in the AddressesProperty declaration.  





OnPropertyChanged() doesn't seem to have any effect either.  Removing the bitwise operations from the 
declaration seems to work, so I am no longer using them in the AddressesProperty declaration.

AaronH replied on Monday, July 18, 2011

Interesting that no one has replied to any of this yet.  I kind of perceive this as a big deal.  My solution doesn't work in all situations either, btw. 

So now what I'm doing is locking the UI with a busy indicator when a root object needs to lazy load its children.  Once the children are loaded, the busy indicator goes away, then the user can double click the root object to edit.  It works, but definitely not ideal.

I guess it's not the end of the world that the UI is now responsible for protecting the state of objects, but it's certainly not ideal and forces the UI to have knowledge as to how those business objects must work so they don't break.

It sure would be helpful for someone from the team to chime in on this. 

I'm sure I haven't been the first nor will I be the last to run into this issue.  It'd also be helpful for CSLA to automatically handle edit level synchronization of asynch lazily loaded children.

Thanks

RockfordLhotka replied on Monday, July 18, 2011

The delay in response could have something to do with me being on vacation. As much as I love CSLA, I really do need to take a break now and then - and there was no real cell coverage where I was fishing and camping with my family (and that was AWESOME btw! :) )

You are describing an interaction between data binding and the objects. Because every UI technology is diffferent (and within each UI technology, not all datagrid controls are equal either), I need to know the UI technology and specific UI control(s) being used to even start to provide insight.

AaronH replied on Monday, July 18, 2011

Oh, this doesn't require an immediate response as I have an acceptable solution right now.  I'm using SL as the UI technology.  The datagrids are the issue.  There are multiple issues, however, so I would encourage you to read through my last 4 posts when you return as I think you might find some valuable insight into reproducing and hopefully fixing the errors.

Have a good trip!

tiago replied on Monday, July 18, 2011

Hi Rocky,

I'm glad you enjoyed your vacation.

RockfordLhotka

The delay in response could have something to do with me being on vacation. As much as I love CSLA, I really do need to take a break now and then - and there was no real cell coverage where I was fishing and camping with my family (and that was AWESOME btw! :) )

Concerning the LazyLoad issue, please have a look at http://forums.lhotka.net/forums/t/10507.aspx

I'm told the asynchronous examples in the ebook have some problems, so a real working exampleof an asynchronous child lazyload would be a must.

Tiago

RockfordLhotka replied on Friday, July 22, 2011

I think the issue in this thread is a misunderstanding about how data binding interacts with the objects. Or perhaps a misuse of a viewmodel - I'm not entirely sure which.

When you get the root object, and manage it with a ViewModelBase<T>, by default the viewmodel will support the Cancel verb. To do this it calls BeginEdit on the root object - raising the entire object graph's edit level to 1.

When you lazy load the child collection, CSLA will ensure the child collection's edit level matches the root - so it will be set to 1 also. That is correct and expected behavior. Because the child object is a collection, this really means that every item in the collection has its edit level set to 1.

When you bind the collection to the UI there's a concept called 'currency'. One item in the collection is current. That item will have its edit level raised by 1 while the user is editing that row in the datagrid. That is normal and expected behavior.

That basic behavior is pretty consistent for WinForms, WPF, and Silverlight data binding.

I am guessing though, that you have a viewmodel for the root object, and another viewmodel for the child collection. And that's fine, but "child" viewmodel types must set ManageObjectLifetime to false to prevent the child viewmodel from elevating the edit level unexpectedly.

So if you are seeing that your lazy loaded collection is raised to EL 2 (all items in the list go to EL 2), that is because some code is calling BeginEdit on the collection. This is almost certainly a viewmodel that has ManageObjectLifetime set to the default value of true.

AaronH replied on Tuesday, July 26, 2011

Rocky, thanks for the follow up on this.  I checked out your lazy loading demo too, which seems to work.  I'm going to make a few modifications to the project to see if I can reproduce the behavior that I spoke of in previous posts.  Where can I send that when I'm done so that you can take a look?

 

RockfordLhotka replied on Tuesday, July 26, 2011

You should be able to attach it to a reply post in this thread.

AaronH replied on Wednesday, July 27, 2011

Rocky I've been trying to upload for a while now, but with no success.  It's only 12K, so i'm not sure what's going on.  Can I email it to you?

Also, here is a short summary of what I've done and how to reproduce:

What I ended up doing was taking your EncapsulatedInvoke project from the DataAccess book and modifying it. 

Because I'm having the issue with Silverlight, I created an SL app and a hosting Web app, so please run the web app so that you can reproduce the behavior.  The web app is using the mock data layer.

There is one view (MainPage) and it uses a VM, but it does not inherit the CSLA VM.

I created an OrderEditList that retrieves ALL OrderEdits, which the VM exposes.

MainPage displays 2 DataGrids; the first grid displays all Orders exposed from the VM, and the second grid displays the LineItems from the currently selected Order.  I changed OrderEdit to lazily load its LineItems, and put a Thread.Sleep in there to simulate lag time on load.

TO TEST:

Double click on either of the date fields of an Order (the properties are now editable).  This does 2 things: it causes the EditLevel of the OrderEdit to change to 1, and it also lazily loads the children. 

After the children have loaded and are displayed in the LineItems grid, double click the ship date to edit.  You will receive and "Edit level mismatch" exception.

This is exactly what I hoped CSLA would handle for me.  I would think that when the children are added, their edit level would be changed to match that of their parent.  As a work around, I disable the Order from being edited in the UI until its children are loaded, but again, I don't think this is a good solution.  This puts too much responsibility on the UI and requires the UI developer to be aware of this bug. 

I should also point out that if you declare the backing field for OrderLineItems with the RelationshipTypes like so:

public static PropertyInfo<OrderLineItems> OrderLineItemsProperty = 
RegisterProperty<OrderLineItems>(c => c.OrderLineItems, RelationshipTypes.Child | RelationshipTypes.LazyLoad);

You will no longer see the items appear in the grid after they have been lazily loaded.

I had to remove them and declare it like this:

public static PropertyInfo<OrderLineItems> OrderLineItemsProperty = 
RegisterProperty<OrderLineItems>(c => c.OrderLineItems);

Thanks again, looking forward to your thoughts.

 

RockfordLhotka replied on Thursday, July 28, 2011

You can send it to rocky at lhotka dot net.

Be aware though, that I'm on an extended vacation. Though I'm poking my head into the forum from time to time, I'm not spending any serious time at the keyboard this summer. So I don't know when I'll look at this to be honest.

The issue is almost certainly in the interplay between the various UI elements and data binding. It sounds like you have multiple datagrid controls, and that means you have multiple currency managers.

The only thing the CSLA lazy loading infrastructure does, is ensure that a newly loaded child is set to the same edit level as its immediate parent. That edit level could be elevated (or not) based on whether it has currency, and whether the viewmodel has called BeginEdit.

I strongly suggest you look at that new lazy load sample I put into svn, and use that as a starting point. Specifically because the objects in that example expose an EditLevel property so you can see how the edit level is affected by currency. You should be able to extend that sample to use two datagrid controls to see if you can replicate the issue you are seeing.

AaronH replied on Friday, July 29, 2011

Thanks, I'll be sending over the solution.  I did look at your sample, and it does work as expected.  The difference is that you're not making any calls to a server though, so I'm wondering if that's the issue?

In any case, the solution that i'm sending is taking what you did in the lazy sample, but instead using your EncapsulatedInvoke project, as it saved me time from having to setup the wcf bindings, web project, etc.  This is a more accurate setup of how our app is currently setup and the only way I can get the error(s) to occur.

AaronH replied on Friday, July 29, 2011

Ok, no go on the file, my email keeps getting bounced.  The file is 4.25mb, is that too large?

RockfordLhotka replied on Friday, July 29, 2011

Doesn't sound terribly big, no... gmail is bouncing it? Or your outbound server?

AaronH replied on Friday, August 26, 2011

Hi Rocky, I was wondering if you've had any time to look at the sample app that I sent to you regarding the LazyLoading bug?

Thanks!

AaronH replied on Sunday, September 18, 2011

Hi Rocky, I was wondering if you've had any time to look at the sample app that I sent to you regarding the LazyLoading bug?

Thanks!

RockfordLhotka replied on Friday, July 22, 2011

Tiago Freitas Leal

I'm told the asynchronous examples in the ebook have some problems, so a real working exampleof an asynchronous child lazyload would be a must.

In the Using CSLA 4 ebook? I would like to know the problems then, because I use the technique shown in the ebook and it works fine for me.

RockfordLhotka replied on Friday, July 22, 2011

Also, to answer the request, I did create a simple LazyLoad sample that is currently in svn:

http://www.lhotka.net/cslacvs/viewvc.cgi/core/trunk/Samples/Silverlight/cs/LazyLoad/

This uses the technique shown in the ebook series, and displays the edit levels of the child objects in the datagrid so you can see how they move up and down as the user edits each row.

Charleh replied on Monday, July 25, 2011

If anyones interested - I've had an issue with a similar lazyload implementation - it stems from the lazyloaded property being queried more than once (simultaneously or thereabouts) by different UI elements - it helps to initialise the fieldmanager immediately after seeing that it has not yet been initialised and use GetProperty to return the result to any additional threads (I've used a little locking to prevent any threads from sneaking past the fieldmanager.fieldexists check).

(Please note this is in Silverlight)

I've had strange behaviour where a routed command would query for execution and see that the property was set, but a binding to the property was using the fallback value as it received a null from the property get. Also I've had the property be set before the null value was even returned (the dataportal ran local and hit the callback before the original thread had returned the null value, which was confusing to say the least... in the watch window the property is set, but the UI hasn't updated?!)

Also you may find that multiple fetches/news are being executed over the dataportal

Simplified it looks like (on client side):

lock(propLock)

{

   if(!fieldmanager.fieldexists(prop))

   {

     loadproperty(prop, null)

//     do fetch/create etc

   }

return getproperty(prop)

}

There's a work item on the codeplex CSLAGen site and this image shows one of the issues

http://cslagenfork.codeplex.com/Project/Download/AttachmentDownload.ashx?ProjectName=cslagenfork&WorkItemId=595&FileAttachmentId=108

This may not be a problem for everyone, but it was an issue for me :)

RockfordLhotka replied on Tuesday, July 26, 2011

I understand the LoadProperty call to create the field in field manager - that's a good suggestion.

The threading lock shouldn't be necessary though. CSLA objects aren't threadsafe. If you have multiple threads hitting this property getter, you have way more problems than just the lazy loading...

Charleh replied on Wednesday, July 27, 2011

Hi Rocky,

Though CSLA objects are not threadsafe, they are ok with async heavy Silverlight because most of the time the UI/user only does one thing at a time. I wouldn't see much benefit in my app in which a multithreaded process would modify an object - but it's sometimes a requirement that multiple UI controls would want to query a property for it's value, and if a form loads it kicks off these property gets almost simultaneously.

The example I posted was very simple - just two fields on a standard data grid which are looking at the same lazyloaded property cause this issue. Not that this would be a real world example, but it highlights how easy it is to get multiple loads kicking off. This could still happen with the LoadProperty(prop,null) in the absence of a lock

RockfordLhotka replied on Wednesday, July 27, 2011

To be precise, they are OK with lots of SL async stuff, because the property code is always used by the UI thread. So while there's async going on, it is never multi-threaded. Therefore the lock statement isn't required.

The LoadProperty to immediate initialize the field manager - that is important, and I'll add that to the ebook as errata next time I do an update on the content.

Charleh replied on Wednesday, July 27, 2011

You're right - I didn't consider the UI thread, I was considering Silverlight as multi-threaded. To be honest I haven't tried it without the lock as I was under presumption that the cause for my issues was due to multiple threads hitting the prop

That's why you're the expert :)

vbbeta replied on Monday, August 01, 2011

Normal 0 false false false EN-US X-NONE HE MicrosoftInternetExplorer4

Hi AaronHi was having the same problem for a very long time but now i do like your work around that you have for the lazyLoad but it seems to me that this approach will only work when creating a new object because if I'm doing a Fetch method it will load the object in the DataPortal_Fetch Method so the logic test of   if (!FieldManager.FieldExists(AddressesProperty))    will all ways be false, unless a new object is being created

 

please let me know if there is any approach while loading an old object

AaronH replied on Monday, August 01, 2011

vbbeta, if you want lazy loading to work, you need to leave the code out of your DataPortal_Fetch method that is loading your addresses. 

It sounds to me like you're eager loading them.

vbbeta replied on Tuesday, August 02, 2011

Basically i did that i just added another if statement to the Lazy-load property Like this

public Setup LocationSetup {
	get {
		if (!FieldManager.FieldExists(LocationSetupProperty)) {
			if (this.IsNew) {
				LoadProperty<Setup>(LocationSetupProperty, Setup.CreateSetup());
			} else {
				LoadProperty<Setup>(LocationSetupProperty, Setup.GetSetup(mId()));
			}
			for (int i = 0; i <= this.EditLevel - 1; i++) {
				this.ApplyEdit();
			}
		}
		return GetProperty<Setup>(LocationSetupProperty);
	}
}

But here is the problem, when I'm adding a new item to the collection in my "Devexpress Winforms GridView" 1 item before the last is getting an EditLevel
 to 1 which causes to thrown an exception Edit level mismatch in copy state, have any noticed this before

 

AaronH replied on Tuesday, August 02, 2011

This is what I'm hoping that Rocky answers for me.  I personally wouldn't manipulate ApplyEdit() as that introduced nasty bugs.  I'm hoping that after a collection comes back asynchronously and set via LoadProperty that the EditLevel of the children are set appropriately.

It doesn't look like you're lazy loading in an asynch fashion, where i believe the issue to be.

If you're synchronously lazy loading children, you shouldn't run into the issue that i'm running into, which is a user edits a root while the children are still loading.  When the children come back from the server and set on teh root object, there is a mismatch between edit levels.

vbbeta replied on Tuesday, August 02, 2011

Thanks for your replies i researched my issue and here is what i discovered;

My error occurs after the object is being saved and the UI is rebinding it so it starts a BeginEdit but my properties already have a value so it don't have a chance any more to Loop through all editLevel and change the State

Copyright (c) Marimer LLC