N-Level Undo Issue / Edit Level Mismatch in AcceptChangesN-Level Undo Issue / Edit Level Mismatch in AcceptChanges
Old forum URL: forums.lhotka.net/forums/t/3674.aspx
JohnB posted on Monday, October 08, 2007
I've got issues with 3.0.2 regarding saving/edit
levels etc. First let me say that it was working with 3.0.1. Here is what I
have:
Notes:
-- myBusObject (of type
BusinessBase)
-- UnbindBindingSource code is exactly the same as Rocky's in
3.0.1/2
-- BindUI is exactly the same as Rocky's in 3.0.1/2
Private Sub RebindUI(ByVal saveObject As Boolean,
ByVal rebindCtrls As Boolean)
'-- Disable events
Me.bsParentObject.RaiseListChangedEvents = False
Me.bsChildObject1.RaiseListChangedEvents = False
Me.bsChildObject2.RaiseListChangedEvents = False
Try
'-- Unbind the UI
UnbindBindingSource(Me.bsChildObject1, saveObject, False)
UnbindBindingSource(Me.bsChildObject2, saveObject, False)
UnbindBindingSource(Me.bsParentObject, saveObject, True)
'-- Save or cancel changes
If
saveObject Then
myBusObject.ApplyEdit()
Try
Dim tempBO As BO
= myBusObject.Clone
myBusObject = tempBO.Save
Catch ex As
Csla.DataPortalException
...
Catch ex As
Exception
...
End Try
Else
myBusObject.CancelEdit()
End If
'-- Rebind the UI if requested
If rebindCtrls Then
BindUI
End If
Finally
'-- Restore
events
Me.bsParentObject.RaiseListChangedEvents = True
Me.bsChildObject1.RaiseListChangedEvents = True
Me.bsChildObject2.RaiseListChangedEvents = True
If rebindCtrls Then
'--
Refresh the UI if rebinding
Me.bsParentObject.ResetBindings(False)
Me.bsChildObject1.ResetBindings(False)
Me.bsChildObject2.ResetBindings(False)
End If
End
Try
End Sub
I get a errors when I cancel or save.
Cancel
According to Rocky in several post, "Never interact with the
business object directly while it is data bound. Instead, always interact with
the binding source object." Well I know that by the time I call CancelEdit, my
BO is no longer data bound but it still throws the exception if I call
myBusObject.CancelEdit(). If I change it to Me.bsParentObject.CancelEdit(), it
works.
Save
I am not making any changes to any of the children, just data on
the parent. I consistently blow up on the myBusObject.ApplyEdit(). The code
breaks in 'BusinessListBase.vb -> AcceptChanges method'.
The error message
says 'Edit Level Mismatch in AcceptChanges', the message and stack trace
says:
"The generic type 'Csla.BusinessListBase`2' was used with the wrong
number of generic arguments in assembly 'Csla, Version=3.0.2.0, Culture=neutral,
PublicKeyToken=93be5fdc093e4c30'."
Any ideas? Again, the code you see above worked with 3.0.1. I have a
grid which is filled with a BLB of BB objects. The user can click a row and
choose Edit. On edit I do the following:
myBO = selectedItem (this is a BB
object)
BindUI()
Does the fact that I am using a BLB instead of a ROLB matter?
ajj3085 replied on Tuesday, October 09, 2007
Search the forum, this has been discussed before. The short answer is that you need to look at teh PTracker sample to see how to unbind and accept changes before saving. You MUST follow that pattern exactly.
It doesn't matter that you're code worked in 3.0.1; there was a bug in that version regarding undo.
JohnB replied on Tuesday, October 09, 2007
ajj3085,
I agree but if you read my post you will see that I am doing exactly as Rocky suggest. The only difference between my code and the PTWin code is resetting the binding source for any child objects. My issue was also with Saving not just Cancel.
After reworking some stuff this AM I am now wondering if I am using the BLB correctly. Are there any best practices for working with BB objects in a BLB?
Thanks,
John
ajj3085 replied on Tuesday, October 09, 2007
Ahh, sorry.
I think this though is your problem:
The generic type 'Csla.BusinessListBase`2' was used with the wrong
number of generic arguments
I'm not quite sure what would lead to that problem, but I'm on 3.0.2 now and am not getting this problem.
JoeFallon1 replied on Tuesday, October 09, 2007
ajj3085: Ahh, sorry.
I think this though is your problem:
The generic type 'Csla.BusinessListBase`2' was used with the wrong number of generic arguments
I'm not quite sure what would lead to that problem, but I'm on 3.0.2 now and am not getting this problem.
I have seen the argument error in a couple of places in my code and also in the Watch window.
Here is what I have learned about it.
A lot of code assumes a collection has a single Item property with a single parameter of index As Integer. For example in a reflection helper class I saw this code:
Member = Type.GetMember(propertyNoIndex, MemberAccess)(0)
GetMember returns an array of MemberInfo objects and the (0) at the end says to use the first one.
If you overload the Item method in CSLA 1.x then it is probable that your code looks something like this:
Item(ByVal index As Integer)
Item(ByVal code As String)
In this case, the reflection code above sees index As Integer as the 0 element and code As String as the 1 element.
Moving to CSLA 2.x - Rocky moved the Item method into his Base class so you do not have to write it (or code gen ) it in your collection classes anymore.
BUT - this changed the way that reflection looks at the array of MemberInfo objects!
It seems that relfection code "sees" the Item method and its overloads in the order of the most concrete class and working up the inheritance chain to the base classes.
So for CSLA 2.x, the reflection code above sees index As Integer as the 1 element and code As String as the 0 element.
To make it even more confusing I added a 3rd overload in my base class which derives from CSLA2 and it pushed the index As Integer to the 2 element and my other overload became the 1 element.
e.g.
Item(ByVal code As String) 0 element
Item(ByVal index As Integer, someParam As String) 1 element
Item(ByVal index As Integer) 2 element
I had a very similar issue with the ObjectListView. The same error was returned because the code used to identify the Item property did not anticipate overloads or moving the index As Integer method into a Base class.
I now use code like this to specifically identify WHICH overload of Item I want to use:
Dim itemProp As PropertyInfo = Parent.GetType().GetProperty("Item", New Type() {GetType(Integer)})
This code always grabs the correct version of Item that uses index As Integer.
Joe
JohnB replied on Tuesday, October 09, 2007
Joe,
Have you subclassed the framework? I did and was wondering if this was the problem although I just tried again going directly to the framework and received the same error.
FWIW, this is what I have in my class in order to subsclass BLB. I believe that this is correct.
Namespace MyNameHere
Public MustInherit Class BusinessListBase(Of T As BusinessListBase(Of T, C), C As {Csla.BusinessBase(Of C)})
Inherits Csla.BusinessListBase(Of T, C)
End Namespace
Thanks,
John
JoeFallon1 replied on Tuesday, October 09, 2007
Yes. I sub-classed the framework. It is highly recommended and very valuable to have.
This is what I have:
Public MustInherit Class MyBusinessListBase(Of T As MyBusinessListBase(Of T, C), C As MyBusinessBase(Of C))
Inherits BusinessListBase(Of T, C)
I am not sure why you have curly braces on your 2nd parameter.
Also, you did not re-name your sub classes - you used the same name as Rocky. I added "My" in front of my sample names. (I really used company initials though).
Joe
JohnB replied on Tuesday, October 09, 2007
The curly braces come from other examples I've seen of people subclassing the framework. Not being an expert on CSLA yet I wanted to make sure that I was doing what others were doing who had success.
As for the naming, I control access to my objects via namespaces. I tend to like it better this way. So far no issues.
John
JohnB replied on Wednesday, October 10, 2007
ok, so I solved my own problem. It appears that my issues were because I was using a BLB as a root for my BO's. I did not think this would be an issue and maybe it's
not but if someone has any ideas on maybe what I may being doing incorrectly please
let me know.
Original:
BLB filled with BB BO's. - Did not work at all
in 3.0.2 but it did in 3.0.1
Solution:
ROLB filled with BB BO's -
Works like a charm!
Again, any ideas on why my first solution would not
work? I read through Rocky's book again to see if I missed anything but I've got
nothing.....
John
ajj3085 replied on Wednesday, October 10, 2007
Your original solution would be fine, as long as your BO's contined in the list were calling MarkAsChild in their constructor. Then you would ONLY call save on the BLB, never on the BB objects.
It sounds like you used BLB to contain ROOT business objects, which is not supported. ROLB should NOT contain BB objects either; if you NEED a list of root objects, you should use ERLB.
In this case, root vs. child indicates 1) the transaction scope; a root object is the root of the transaction, while its child object updtes WILL take place within the transaction and 2) the child objects CANNOT be saved independantly; it only makes sense to save them at the same time as the root.
I would check out the book again if that's not clear.
HTH
Andy
JohnB replied on Wednesday, October 10, 2007
I actually had a typo. The solution is a ROLB of ROB objs. When the user selects an item I retrieve a BB obj. As for the BLB, your explanation would expain my problem.
Thanks for your help.
ajj3085 replied on Wednesday, October 10, 2007
Ahh, ok. That makes sense then, although I'm suprised the compiler didn't point out the problem immedately.
JohnB replied on Wednesday, October 10, 2007
Not to prolong this any further but what would you expect the compiler to "say"?
Also I wanted to jump back to the subject of ROLB. I just copied this from Rocky's book:
ReadOnlyListBase Class
Like the ReadOnlyBase class, ReadOnlyListBase is quite simple to create. It is designed to make it
easy for a business developer to create a business collection that doesn’t allow items to be added
or removed. Presumably, it will be used to contain read-only child objects, but any type of child object is allowed.
So is it considered to be a best practice to NOT to stuff anything but a ROB obj in a ROLB?
ajj3085 replied on Wednesday, October 10, 2007
Oh, you're right. I thought it was like BLB, where it required that objects contained in the list would inherit from ROB. My mistake.
Copyright (c) Marimer LLC