Question About Undoing A Child Object

Question About Undoing A Child Object

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


cmay posted on Monday, June 12, 2006

Sorry for plastering this board with questions.  I am trying to learn this stuff and don't know anyone who has worked with CSLA.

I am having trouble getting the undo functionality to work with a child object, everything else works fine.  I wondering if this this not supported, or if I am screwing up the implementation, or if I am just doing it totally wrong.

I have a Driver object who has a Car object as a child.  The situation I am working through now is where someone is editing the Driver (they can change his Car to be a different Car from a list of cars).

Dim carlist As Cars = Cars.GetCarsList()

'*** test some undo stuff

Dim d As Driver = Driver.GetDriver(3)

MsgBox(d.Car.ToString)

d.BeginEdit()

d.Car = carlist.item(10) '*** change to a new car

d.CancelEdit()

MsgBox(d.Car.ToString) '*** should be the same as earlier

The 2 msgboxs should show the same value right?  But the second one shows the name of the new car.

 

xal replied on Tuesday, June 13, 2006

Is car a child object of driver? what is Cars? a name value list? a readonly collection?

By the looks of it it seems as if Car where a child object of Driver. All Child objects or child collections should be exposed as readonly... replacing them with another object could shield unexpected results such as what you're seeing right now. You should be changing a value inside the property that indicates a change of car. This will mark the child object dirty and thus it'll be saved. With your approach you're replacing a child object and noone knows that there was a change.
Also, Undo doesn't work because internally, the object that you set as car was never part of the undo, so it doesn't contain undo information.

Andrés

cmay replied on Tuesday, June 13, 2006

Xal, thanks for writing back.

I'm getting closer, but maybe I am still designing it wrong.

To answer your question: the way I had it was Car was a child of Driver accessible through a property (read/write).  Cars was a BusinessListBase inherited collection of "Car".

Because Car didn't inherited from BusinessBase and not ReadOnlyBase, it implemented IUndoableObject, so when the Driver was taking a snapshot of itself it wouldn't include the Car, instead it would tell the Car to take a snapshot of itself at that moment, which doesn't matter if I later replace that Car object with another Car.

So I changed my code to use a CarInfo class that is a ReadOnlyBase and things seem to be working, but based on your comments I am wondering if my Driver should have a read/write Car child object at all.

Right now, the way it is working is, Driver has a child Car object of type CarInfo.  To edit the Driver I databind CarList, a collectoin of CarInfo, to a dropdown and bind the dropdown to my Driver.Car object based on Car.ToString = combobox.text.

When creating the drive I debated on if I should have a child Car object or just have CarId, CarModelName, CarBrandName properties on the Driver.

If I would have done that, I think databinding would have been easier b/c I could have used a combobox bound to a NameValueList instead of a ReadOnlyList.  What do you think?

You also said that child objects should be exposed as readonly and that I should be changing another value that indicates a change in car?

I could do this by having a readonly Car property and a read/write CarId property, and do all my databinding on CarId.  The only problem with this is that I would need to fetch a new Car every time CarId was changed right, because if someone changed the dropdown and CarId went from 10 to 11, then the Car child object would be incorrect at that moment, as it would be the Car with an Id of 10, not 11, so I would need to hit the database again to get the correct car.

Is this the approach I should be following?  Or should I not even bother carrying around a Car object, and just carry the CarId, CarModelName, and CarBrandName on my Driver object?

This is the other post I have talking about this which might give more insight into what I am trying to do.  http://forums.lhotka.net/forums/thread/1634.aspx

Again thanks so much!

 

xal replied on Tuesday, June 13, 2006

It is very important that child objects are exposed as readonly.
One of the main reasons is the way you're handling persistance.
For starters, if you have a Car property that is actually of type CarInfo (your readonly object), then your child is not handling it's own update. So you're breaking a rule:
Child objects should handle their own persistance. Otherwise the parent acquires the responsability to persist the child and then you get into an ugly mess.
So, if you expose the child as read write, and then replace it, you can't rely on your child's IsNew and IsDirty, because you can't really know when and where the object was created.
So, you can:
-Expose just car properties in the root
-Have a child and bind your controls to yourBo.Child.Child_Value. You'll need to be able to update the other properties of your child when you update the value (which can be a name or an id, or whatever you use). So you can:
1) Have a cached list of cars that you can use to refresh the children's readonly properties (like car name, type, whatever).
2) Have a Public Sub ChangeCar(ByVal newCar as CarInfo). Inside it you can update the whole child by absorving the values exposed in CarInfo.

The most important thing is that you clearly define the responsability of each object. If you still want to update the driver's car data in the root's update, then there's no point in having a child object... which by the sound of it, is probably where you want to go because the car child only needs to persist the relation between car and driver.
If the child also has other responsabilities, like setting the colour and the type of seats and wheels and whatever, then having a child is probably best because otherwise the root will have a very large responsability.

I hope this clarifies matters for you.

Andrés

cmay replied on Tuesday, June 13, 2006

Thanks Xal!

Copyright (c) Marimer LLC