You must mark any parent field with the NotUndoable attribute so n-level undo ignores that field.
You may need to (and probably should) mark parent fields as NonSerialized as well. Though the serializer honors circular references, they do tend to expand the size of the serialized byte stream. If you mark the field as NonSerialized, then make sure to override the OnDeserialized method and re-hook the reference, otherwise your references will get lost during the serialization/deserialization process.
If you use Windows Forms data binding you must make
n-level undo work. No option.
(well, in CSLA 3.0 there’s an option because you can set DisableIEditableObject
to True to block automatic use of undo by data binding, but in that case you’ll
find that the UI doesn’t quite work like you expect unless YOU call
BeginEdit/CancelEdit/ApplyEdit appropriately…)
But to make n-level undo work all you need to do is put the NotUndoable
attribute on your parent fields.
The serialization issue is only important if you use a remote
data portal server or call Clone (which is recommended when saving your objects
when using a local data portal configuration).
In other words, the n-level undo fix is trivial. The
serialization fix is slightly harder, but is necessary for a couple
common/important persistence scenarios.
Rocky
You'll notice that I never actually do serialization or deserialization. Instead I use the BinaryFormatter or NetDataContractSerializer to do any real (de)serialization.
n-level undo serializes individual objects only - never an actual graph. That avoids the complexity.
I did once try to write a complete serializer. Serialization is relatively easy. Deserialization (if you ignore ISerializable) is tricky, but possible - even with circular references. But as soon as ISerializable enters the picture you are in serious difficulty, because you need to be able to create objects without running their constructor or any other initialization code. Without that ability, you can't avoid an ugly circular reference issue.
Long after I abandoned that project (because I wanted an XML serializer, and got one with WCF), I did find the answer. Unfortunately I don't remember the type/method name now, but buried deep in .NET there's a type that has a method that can create an object without initializing that object. That's the method used by BF and NDCS to create an object, and then they manually invoke the "constructor" after they've done all the fix-ups needed to resolve circular references.
It is also the case that .NET includes some serialization helper objects. If you use Reflector against the BF you can find them. I didn't use them, because I wanted to see how it worked from the bottom up, but using them can help a lot, because they do the fix-up work for you, etc.
Of course my answer could be totally going in a different direction from the intent of your question...
Yeah, I was afraid I was going off into left field with my last
answer J
If you look at CSLA itself (specifically BusinessListBase) you’ll
see what I mean. It has a deserialization handler where it loops through its
children to call SetParent(). This re-links the child’s parent reference
back to the collection.
Rocky
I think you are missing some relevant bits.
Either you are
<Serializable()> _
Public Class Study
Inherits BusinessBase
Or you are
<Serializable()> _
Public Class Study
If you inherit from BusinessBase, then you are part of the
n-level undo cycle itself, and your object won’t be serialized by n-level
undo. Instead, UndoableBase uses reflection to trap your fields.
If you do NOT inherit from BB, then you will be serialized using
the BinaryFormatter, but you won’t be able to override OnDeserialized()
because that comes from BB. Instead, you’ll need to declare a method with
an attribute (look at BB for an example) so the BinaryFormatter calls you
directly.
In the former case, where you do inherit from BB,
OnDeserialized() will only be called due to a Clone() or Save() call (pretty
much). You don’t typically need to reset the parent on a CancelEdit() or
ApplyEdit() because the NonUndoable attribute tells n-level undo to entirely
ignore the specified field. This means it is never touched – not cleared
or anything.
So when inheriting from BB you do need to reset the parent
on deserialization. You do not need to reset the parent due to n-level
undo.
Rocky
Right, Save() will cause serialization and deserialization. That
should cause your method to run.
If you are using a local data portal, you are probably saving a
clone – so it is the Clone() call that actually triggers the process. If
you are using a remote data portal it is the data portal that triggers the
process.
If you are using a local data portal and not calling Clone(),
then no serialization would occur.
Rocky
Looking at your code, you are not doing a Clone(). So if you are using a local data portal then no serialization occurs. That probably explains why the method is never invoked
But if that is the case, then neither serialization nor undo are clearing the field, so you must have code (perhaps in your DP_XYZ methods) that is somehow clearing the field.
Copyright (c) Marimer LLC