Hello,
I have a small, yet increasingly, complex application begun
using Flex DataServics / Tomcat / Spring / Hibernate, and am
running into what apparently are not uncommon limitations with
regards to the complexity of the data model when using
DataServices.
The skinny: when deleting an item from a managed collection,
instead of the client issuing the correct 'update' operation on the
collection, some internal Adobe code detects something that results
in the entire collection being released, the consumer being
unsubscribed, and the destination being disconnected...
By and large things work well, but I recently added in some
inheritance to a particular table that may or may not be causing me
trouble.
Before getting overly detailed as to my exact data model,
let's try the following summary:
1) table "Presentation" has a collection of "slides"
2) table "Slide" is extended by table "SlideMaster" and
"SlideReference", joined on a shared primary key
3) table "SlideMaster" has a collection of "slideElements",
and "slideReferences"
4) table "SlideReference" simply points back to a parent
"slideMaster"
For my destination configuration, I actually define a
destination for each table: spring.presentation, spring.slide,
spring.slideMaster, spring.slideReference, etc.
Note: all DataServices are set to autoCommit = false, and
autoSync = true.
Note that this is not actually the top of my object tree, but
let's just deal with the notion of adding and removing Slides from
a Presentation.
I can properly add slides by:
mySlide = new SlideMaster();
mySlide.presentation = myPresentation;
myPresentation.slides.addItem(mySlide);
// then do a commit
This works fine.
However, when I attempt to remove a slide:
index = myPresentation.slides.getElementIndex(mySlide);
myPresentation.removeItemAt(index);
What happens is very odd and very frustrating.
I have ALL of the debug logging enabled, so the first thing I
see is a message queued to destination spring.presentation,
operation = update. This is as expected.
Next, I see the propertyChangedEvent handlers called on my
DataServices, indicating that commitRequired has gone from false to
true, again as expected.
However - when not stepping through breakpoints, etc., the
next thing that happens is a subsequent call to the
properyChangedEvent handlers, indicating that commitRequired is now
FALSE, and this is followed by the client issuing the following log
messages:
-------------------- logging start -------------------
4/1/2008 14:37:32.233 [INFO] mx.messaging.Consumer
'cds-consumer-spring.slide-null' consumer unsubscribe.
4/1/2008 14:37:32.235 [WARN] mx.messaging.Consumer
'cds-consumer-spring.slide-null' consumer channel disconnected.
4/1/2008 14:37:32.236 [INFO] mx.messaging.Producer
'ds-producer-spring.library' producer sending message
'296B7FA3-B4AB-2F9E-5FE8-0B479ACC829B'
4/1/2008 14:37:32.238 [DEBUG] mx.messaging.Channel 'my-amf'
channel sending message:
[... operation = release; destination = spring.slide ...]
4/1/2008 14:37:32.240 [INFO] mx.messaging.Consumer
'cds-consumer-spring.presentation-null' consumer unsubscribe.
4/1/2008 14:37:32.240 [WARN] mx.messaging.Consumer
'cds-consumer-spring.presentation-null' consumer channel
disconnected.
4/1/2008 14:37:32.240 [INFO] mx.messaging.Producer
'ds-producer-spring.library' producer sending message
'ADABC35E-C24F-283B-46DC-0B479AD08F51'
4/1/2008 14:37:32.242 [DEBUG] mx.messaging.Channel 'my-amf'
channel sending message:
[... operation = release; destination = spring.presentation
...]
-------------------- logging end -------------------
Basically, when I remove mySlide from the
myPresentation.slides collection, after DataServices queues up the
correct udpate message and sets commitRequired to true, something
else happens way beneath the covers that results in this errant
cancellation of the update, and subsequent release of the
collections.
I attempted to dig deeper by stopping execution at the point
at which the second call was made to the propertyChangedEvent
handler, and found the reason for this behavior has something to do
with some internal Adobe classes, and seems most specifically due
to something called releaseItemIfNoDataListReferences, which seems
to get something confused... either as though the entire
myPresentation.slides collection should be released, or... or what,
I'm not sure, but it is at this point, if I step through the code
(without of course being able to see the code, since I don't have
the source) that things change and those releases occur.
Here is the stack at the point at which my PropertyChange
handler is notified that commitRequired is now false:
com.nv.client.model::PresentationsProxy/handlePropertyChange
flash.events::EventDispatcher/dispatchEventFunction [no
source]
flash.events::EventDispatcher/dispatchEvent [no source]
flash.events::EventDispatcher/dispatchEventFunction [no
source]
flash.events::EventDispatcher/dispatchEvent [no source]
flash.events::EventDispatcher/dispatchEventFunction [no
source]
flash.events::EventDispatcher/dispatchEvent [no source]
mx.data::DataMessageCache/checkCommitRequired
mx.data::DataMessageCache/removeMessage
mx.data::ConcreteDataService/internalReleaseItem
mx.data::ConcreteDataService/
http://www.adobe.com/2006/flex/mx/internal::releaseDataList mx.data::ConcreteDataService/
http://www.adobe.com/2006/flex/mx/internal::releaseAssociations mx.data::ConcreteDataService/
http://www.adobe.com/2006/flex/mx/internal::releaseItemIfNoDataListReferences mx.data::DataList/removeItemAt
mx.collections::ListCollectionView/removeItemAt
com.nv.client.model::PresentationsProxy/removeSlide
com.nv.client.mediators.views::PresentationMapMediator/deleteSlideHandler
flash.events::EventDispatcher/dispatchEventFunction [no
source]
flash.events::EventDispatcher/dispatchEvent [no source]
mx.core::UIComponent/dispatchEvent
com.nv.client.view.presentations::PresentationTableSlideCell/deleteSlide
com.nv.client.view.presentations::PresentationTableSlideCell/menuHandler
flash.events::EventDispatcher/dispatchEventFunction [no
source]
flash.events::EventDispatcher/dispatchEvent [no source]
mx.core::UIComponent/dispatchEvent
mx.controls::Menu/dispatchEvent
mx.controls::Menu/mouseUpHandler
I was able to work around this, somewhat, by doing the
following:
index = myPresentation.slides.getElementIndex(mySlide);
mySlide.presentation = null; // note this is not allowed in
the DB
myPresentation.removeItemAt(index);
mySlide.presentation = myPresentation;
// do commit
This seems silly, of course, but if I remove the reference to
the parent Presentation from the Slide before removing it, then
those nasty unsubscribe/release collection operations are not
triggered, and the slide is deleted successfully.
However - IF I first delete a slide, and then attempt to add
a slide, I run into a new problem, in that the client for some
reason injects the primary key value of the DELETED slide into the
upbound "create" opeartion for the NEW slide.
So - if I delete slide with id=28, then create a new slide,
the first thing I see is a queued message for a new slide with
id=0, as expected, and I then see a message queued to update the
presentation.slides collection. However, when I commit, I see the
actual message sent to the server has changed from the queued
message, and instead of id=0 for the new slide, I now see id=28.
I am totally perplexed by this, and of course I suppose it's
possible that my inhertance scheme is confusing something
somewhere, and I'd hate to think that after investing the last
month of my time getting past various other idiosyncrasies of Flex
LCDS, that I'd have to rewrite everything using RemoteObjects or
some other solution.
Any information would be greatly appreciated, and I am happy
to provide many more gory details as necessary.
Thanks in advance!
Greg