Ok, I spent the evening scouring every framework and the application
to make 100% certain that I am not violating any EOF commandments,
and although it is always possible that I missed something somewhere,
I am pretty darn sure I am clean. Furthermore,
DebugGroupMultithreading isn't spitting out any warnings, so I assume
I'm safe there. I'm not using a shared editing context anywhere. As
far as I know, my editing contexts never get garbage collected until
the session expires (I have two that I use, the default editing
context, and an editing context that is nested in the default which
is referenced in session and locks and unlocks in awake and sleep).
I've managed to come up with a workflow that reliably causes the
exception, and over the course of running it dozens of times with
different debugging statements, I've learned a few things. I'm
loathe to call this a bug in EOF, because there are so many unknowns
and complexities, but it sure seems like a good candidate for that
label. Here is the scenario:
I have an edit page for a catalog item. The catalog item has one or
more KitQuantity's, and each KitQuantity has an InventoryItem:
CatalogItem <-->>KitQuantity<<-->InventoryItem
A KitQuantity is a glorified join table which relates the catalog
item to many inventory items, plus keeps a little bit of other
information such as how many of each inventory item belong in the
catalog item definition. The relevant part here is the piece where I
add KitQuantities. If I have an existing catalog item, I load the
edit page and pass it the catalog item to be edited. Within the edit
page's setCatalogItem method, I get local instances of all the
relevant pieces within my nested editing context (_nestedEC) using
EOUtilities.localInstanceOfObject/localInstancesOfObjects. I list the
KitQuantities on the edit page, and have a delete button beside each
one. When the delete button is clicked, the following code is executed:
public WOComponent removeItem() {
_nestedEC.deleteObject( _kitQuantity );
_nestedEC.saveChanges();
ec.saveChanges();
setValueForBinding( "Changes Saved", "message" );
return context().page();
}
It works great when I load an existing Catalog Item and delete it's
KitQuantity relationships one by one. In the same page I can do a
search on inventory items and select inventory items (and a quantity)
to add to the catalog item via KitQuantity relationships. I create
my KitQuantity using EOUtilities.createAndInsertObject with
_nestedEC, set the quantity attribute,
addObjectToBothSidesOfRelationshipWithKey for both the CatalogItem
and the InventoryItem, saveChanges() on _nestedEC, and then
saveChanges on session.defaultEditingContext():
public WOComponent addItemToKit() {
_kitQuantity = (KitQuantity)
EOUtilities.createAndInsertInstance( _nestedEC, "KitQuantity" );
_kitQuantity.setQuantity( proposedQuantity );
_kitQuantity.addObjectToBothSidesOfRelationshipWithKey
( catalogItem, "catalogItem" );
_kitQuantity.addObjectToBothSidesOfRelationshipWithKey
( inventoryItem,
"inventoryItem" );
localSession.addToMessage( proposedQuantity + " " +
inventoryItem.sku()
+ " added to kit." );
}
_nestedEC.saveChanges();
ec.saveChanges();
return context().page();
}
This works great also. The KitQuantities are visibly represented on
the page, they are definitely in the database, and I can even print
out the snapshot for the items for both editing contexts as they are
created, and everything is perfect. If I were to quit the
application, restart, and come back to this page and edit this item,
I could delete the KitQuantities without a care in the world. But if
I immediately start deleting the NEWLY CREATED KitQuantity items, I
run into problems. Usually (but not always) the first one deletes
ok, but at some point in deleting the remaining ones, I get the
following exception:
java.lang.IllegalStateException: recordDeleteForObject:
com.webobjects.eoaccess.EODatabaseContext
[EMAIL PROTECTED] failed to find a
snapshot for EO with Global ID:_EOIntegralKeyGlobalID[KitQuantity
(java.lang.Integer)1216] that has been deleted from
[EMAIL PROTECTED] Cannot delete an
object that has not been fetched from the database
[2007-04-19 23:06:49 EDT] <WorkerThread9>
java.lang.IllegalStateException: recordDeleteForObject:
com.webobjects.eoaccess.EODatabaseContext
[EMAIL PROTECTED] failed to find a
snapshot for EO with Global ID:_EOIntegralKeyGlobalID[KitQuantity
(java.lang.Integer)1216] that has been deleted from
[EMAIL PROTECTED] Cannot delete an
object that has not been fetched from the database
at com.webobjects.eoaccess.EODatabaseContext.recordDeleteForObject
(EODatabaseContext.java:4926)
at
com.webobjects.eoaccess.EODatabaseContext.recordChangesInEditingContext(
EODatabaseContext.java:6059)
at
com.webobjects.eocontrol.EOObjectStoreCoordinator.saveChangesInEditingCo
ntext(EOObjectStoreCoordinator.java:412)
at com.webobjects.eocontrol.EOEditingContext.saveChanges
(EOEditingContext.java:3226)
at er.extensions.ERXEC._saveChanges(ERXEC.java:947)
at er.extensions.ERXEC.saveChanges(ERXEC.java:870)
at EditKitHelper.removeItem(EditKitHelper.java:77)
...
Here the editing context identified by "b88745" represents the
session's editing context, and the exception is thrown when I call
saveChanges on the default editing context within the removeItem
method. Furthermore, if I print out ec.deletedObjects() right before
calling ec.saveChanges (and after _nestedEC.saveChanges), the item to
be deleted is there!:
ec.deletedObjects(): (<KitQuantity pk:"1216">)
So it appears that the nested EC is flushing its information to the
default ec correctly, and I can tell that the editingContext's
snapshots are fine until very shortly before the operation. Just in
case there was something funny going on in the EO's, I commented out
every line of code from CatalogItem, InventoryItem, and KitQuantity
(the three classes being dealt with here), so that effectively they
were all blank implementations, and I still get the same result.
This would seem to rule out any possibility of EOF commandment
violation.
At this point I am over trying to understand what is going on or walk
on eggshells to make sure I don't offend EOF's delicate
sensibilities. I'm under a deadline and I'm seriously considering
just cutting EOF out of the loop and doing the whole thing using
straight JDBC, but I hear (and somewhat know from experience) that
that approach is a slippery slope to misery, so I thought I would put
out a detailed description of what I'm doing just in case anyone sees
something glaringly obvious or stupid in my methodology (always a
distinct possibility). Any help or thoughts are greatly appreciated.
Thanks,
Mark
On Apr 19, 2007, at 4:34 PM, Chuck Hill wrote:
On Apr 19, 2007, at 12:54 PM, Steven Mark McCraw wrote:
Hey Chuck,
/Library/Receipts tells me I'm on the 5.3.3 update.
I have been running with DebugGroupMultithreading for a few days
now, and nothing seems to have changed, so I assumed everything
was ok there, but it could just be that I set things up wrong. I
just added the following lines to my Application constructor:
NSLog.debug.setAllowedDebugLevel
(NSLog.DebugLevelInformational);
NSLog.allowDebugLoggingForGroups
(NSLog.DebugGroupEnterpriseObjects |
NSLog.DebugGroupMultithreading);
Should that do it, or is there something else I need to do?
I think that should do it.
Otherwise, I will go through and clean out anything anywhere that
overrides a setter or getter and changes the data being set/get,
and I'll see if that makes a difference.
Thanks for the suggestions.
The only other things that I can think of that might _possibly_
causing something like this are
- misuse of the shared EC
- somehow keeping a reference to an EO after its editing context
has been disposed
- holding a lock on an EC for too lock and it getting out of synch
with the snapshots
Chuck
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Webobjects-dev mailing list (Webobjects-dev@lists.apple.com)
Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/webobjects-dev/archive%40mail-archive.com
This email sent to [EMAIL PROTECTED]