Does switching from Local to Remote affect binding?

Does switching from Local to Remote affect binding?

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


lotrij posted on Monday, January 15, 2007

Hey,

I recently began testing remoting and found that BeginEdit/EndEdit are called differently on my business objects (than they were called while my project was running locally).  The thing that makes this particularly odd is that my tests should have nothing to do at all with whether the business objects are local or remote.  I'm just deleting a few objects in a child collection and calling CancelEdit on the BindingSource corresponding to the parent object.

I have an EditableRootListBase of BusinessBase objects which each have a child BusinessListBase collection of BusinessBase objects. 

The EditableRootListBase is bound to an Infragistics UltraGrid.  The current object in the UltraGrid has its properties bound to some controls on a different tab.  That object's child collection is bound to another UltraGrid, also in the other tab.

I have some buttons that, when pressed, allow the data in the second tab to be edited, saved, undone, etc.

It took a while to get the child grid to work properly (many hours of break points in UndoableBase's CopyState,UndoChanges, and AcceptChanges methods), but I was able to get it all working locally.  Then when I set up remoting the order of BeginEdit/EndEdit or whether or not they are called at all has seemed to change.  So, my workarounds don't work anymore. Sad [:(]

When I switch back to running locally they all work again so I'm pretty sure it has something to do with remoting.  But how does using remoting play a role in code that doesn't use the DataPortal (it doesn't hit any of my DataPortal_XYZ methods when I run it locally with breakpoints in them)?

Any ideas?

 

Thanks,

Jonathan

 

ajj3085 replied on Tuesday, January 16, 2007

An EditableRootListBase subclass is meant to save changes immediately as they happen.

Because each row in the ERLB is a root object, it can be commited by itself, without worrying about the other objects in the collection.  Because of this, ApplyEdit will save the row back to the database. 

If all the data in the grid must be saved as a single transaction, you'll need to use BusinessListBase instead, and of course change the class which the collection will contain to child objects (by calling MarkAsChild in the constructor, typically).

ERLB is a pretty rare collection to use at all, but it was added because there are some cases where this behavior is desired.

HTH
Andy

lotrij replied on Tuesday, January 16, 2007

Hey,

Thanks for the response.

In the testing that I described above I don't use ApplyEdit/EndEdit.  That's what makes it so confusing to me.  I use CancelEdit on the BindingSource to undo the deletes.  So nothing related to the DataPortal at all should come into play at this point, or so I would think at least.

I think the part that is changing in particular is when I call RemoveAt(currentIndex) on the child binding source.  If it's running locally, if the currentIndex = 0 then calling RemoveAt causes an extra CopyState to occur, if the currentIndex > 0 then calling RemoveAt just removes the current item.  If it's running remotely, an extra CopyState doesn't seem to occur in either case.  My workaround was to manually UndoChanges on the object before removing if the current index = 0.  This doesn't work if its running remotely.

Another difference seems to be that when I call CancelEdit on the parent object locally, a BeginEdit is immediately called on the parent object again.  Meanwhile, the CancelEdit while running remotely doesn't cause a BeginEdit to be called on the parent object again.

It doesn't make sense to me.  The only change at all between these two scenarios, from my perspective, is 3 lines in my app.config to switch from local to remote.

Any ideas on what could be wrong?

I'm wondering if maybe it's just the initial binding that's different.  When I do binding through the VS designer, it automatically creates a BindingSource for each hierarchy.  In the form's load event I just do something like ParentBindingSource.DataSource = ParentList.GetList().  Could this initial line behave differently in both cases?

 

Thanks,

Jonathan

lotrij replied on Tuesday, January 16, 2007

Hey,

Edit:

I was running tests locally when I thought I that they were remote.  So it's still not working at the moment.

Sorry about that.

 

Thanks,

Jonathan

ajj3085 replied on Tuesday, January 16, 2007

lotrij:
In the testing that I described above I don't use ApplyEdit/EndEdit.  That's what makes it so confusing to me.  I use CancelEdit on the BindingSource to undo the deletes.  So nothing related to the DataPortal at all should come into play at this point, or so I would think at least.


The grid will call those events for you though. 

lotrij:
I think the part that is changing in particular is when I call RemoveAt(currentIndex) on the child binding source.  If it's running locally, if the currentIndex = 0 then calling RemoveAt causes an extra CopyState to occur, if the currentIndex > 0 then calling RemoveAt just removes the current item.  If it's running remotely, an extra CopyState doesn't seem to occur in either case.  My workaround was to manually UndoChanges on the object before removing if the current index = 0.  This doesn't work if its running remotely.

As I said in my previous post, it doesn't sound like you're using the appropriate subclass to do what you want.  You shouldn't be coding up any 'workarounds' to the behavior your expreiencing.  Instead, you should look at what behavior you want, and use the appropriate subclass, which sounds like BusinessListBase instead of ERLB.

lotrij:
Another difference seems to be that when I call CancelEdit on the parent object locally, a BeginEdit is immediately called on the parent object again.  Meanwhile, the CancelEdit while running remotely doesn't cause a BeginEdit to be called on the parent object again.

It doesn't make sense to me.  The only change at all between these two scenarios, from my perspective, is 3 lines in my app.config to switch from local to remote.

Any ideas on what could be wrong?

I'm wondering if maybe it's just the initial binding that's different.  When I do binding through the VS designer, it automatically creates a BindingSource for each hierarchy.  In the form's load event I just do something like ParentBindingSource.DataSource = ParentList.GetList().  Could this initial line behave differently in both cases?

Again, I think your confusion lies in what purpose ERLB servers.  From what you've described, it doesn't sound like that's the approprate subclass for your needs.   N-level undo and remoting have nothing to do with each other, except when you're using ERLB, because applying an edit should save the data to the database immediately.  From my understanding, that's the behavior which the class was intended to provide, because the standard BLB doesn't act that way, and there were a few people that needed ERLB. 

Andy

lotrij replied on Tuesday, January 16, 2007

Hey,

Thanks for the response.

ApplyEdit/EndEdit seemed to be called either when I change the active row in the grid or when I call EndEdit on the corresponding binding source.  This is ok since for the parent grid I don't allow row changes after the edit button has been clicked.  I call EndEdit on the binding source myself when the user clicks the save button.  EndEdit causes the current parent item to be saved to the database, which is the way that we want the program to work.

I'm not sure if the problem is in which types of objects I picked.  I chose ERLB for the parent list because I want each parent object to save its changes to the database.  I chose BLB for the child list because I want the user to edit the items in it at the same time as a particular parent object and I want to send it to the database at the same time as the parent object.  Is this the wrong use of objects?

The undo seems to work somewhat intuitively (I just need 1 layer).  When I bind the parent list to the parent binding source it calls BeginEdit on the current parent item  This causes the child list within the current parent item to CopyState, which causes the child objects to CopyState also.  Then, the child binding source calls BeginEdit on its current child object, which causes it to CopyState.  So the current child object has 2 layers on the undo stack.  As I switch rows in the child grid it calls EndEdit on the previous curren then BeginEdit on the new current, so the current child always has 2 layers of undo while the others have 1 layer. 

This made sense to me since I figured both the entire parent edit or the current child edit could then be saved or undone.  The problem is that the binding sources have some odd behavior.  Calling EndEdit on the child binding source results in an immediate BeginEdit (maybe its the grid) being called (so I use SuspendBinding on the child binding source a lot, to keep that 1 layer off of the child object's stack).  Further, when you CancelEdit/EndEdit on the parent binding source, BeginEdits are called in weird ways on the child objects depending on whether or not you are on the first item from the binding source's (not the grid's) perspective.

I spent a lot of time watching breakpoints in the ApplyChanges/UndoChanges/CopyState methods to work around the weird BeginEdits.  And it all worked locally -- I was able to edit parent objects and their inner child collections and completely undo the changes while having the expected edit level and undo stack.  But switching to remoting has changed the order that ApplyChanges/UndoChanges/CopyState are called in.  This is the part that confuses me.  It doesn't make sense (to me at least) that switching from local to remote would change the order of ApplyChanges/UndoChanges/CopyState, but this seems to be the case.

It's possible that I'm using the wrong objects for what I want (I'm new to CSLA so I don't have much experience chosing objects yet).  But, even with the wrong objects, why would a switch from local to remote change the order of ApplyChanges/UndoChanges/CopyState?

 

Edit:

Is there something that I could be forgetting to do in my business objects that wouldn't be noticed when I'm running locally?  Something that would affect binding?

 

Thanks,

Jonathan

lotrij replied on Tuesday, January 16, 2007

Hey,

I put a break point in after just fetching my parent list and I noticed that:

when running locally mNonSerializableSavedHandlers has a value

when running remotely mNonSerializableSavedHandlers doesn't have a value

 

In my parent business objects I have a handler for the Saved event (I have them merge in the new, saved object to get the ID).  So it seems that the remote object loses this event handler while the local version keeps it.  It probably isn't related to the problem above, since it doesn't involve saving.  But, why is the event handler lost?  Do I have to manually readd it to each business object each time I fetch?

Does the business object lose anything else that might affect binding?

 

Thanks,

Jonathan

Brian Criswell replied on Tuesday, January 16, 2007

Are you re-hooking up the events in OnDeserialized?

lotrij replied on Tuesday, January 16, 2007

Hey,

I tried overriding OnDeserialize to add the event handlers back and it is working nicely.

I'm still not sure what is causing the binding problem I've been having.  I did notice though that the undo stacks for remote and local runs have a different number of bytes on them just after my parent list is set as the datasource of the binding source.

Just after setting the parent list as the data source of the binding source while running locally results in 1 undo layer of 919 bytes in the first parent object.

Just after setting the parent list as the data source of the binding source while running remotely results in 1 undo layer of 1131 bytes in the first parent object.

I'm going to try stepping through CopyState() to see what might be happening.


Edit:

The size difference is just because I don't use any validation rules.  Locally, ValidationRules is never used so the rules collection is never instantiated.  Remotely, after deserialization  the OnDerializedHandler does use ValidationRules so the rules collection does get instantiated.

Copyright (c) Marimer LLC