Are other people using nested editing contexts?
Yes, in reasonably heavily used production applications. BUT the big difference that I see is that you seem to create on per session. I usually create one per function/page.
This seemed like the way to go to me, too, at first. But then I read (see link below) that you couldn't reliably lock an editing context in a page's awake/sleep like in session, because those might not always get called with a one to one correlation (that is, you might somehow have two awake() invocations or two sleep() invocations in a row). Since attributes on EOs in that ec will be getting set when the form values are pulled, I didn't know how to lock correctly if I couldn't lock/unlock in awake/sleep, so I moved all that business to session, as the post suggested.
"In general you are better to lock EC's in the session (if you've got one) rather than the component" and
"One thing to watch out for is that EC locking on the page's awake() and sleep() doesn't really work, because awake may be called more often than sleep."
So how do you get around the locking issues at the page level? Do you just use the project wonder classes, which appear to lock everything for you? I finally found a workaround that works, taken from a post in like 2002. In Application's constructor, I call
EODatabase.disableSnapshotRefCounting();
HACK! :-)
Agreed :) But why does it work? If the application runs great without snapshot reference counting, it tells me that the problem lies in the way EODatabase is managing its snapshot dictionary. Specifically in this instance, it seems to be decrementing the count of things pointing to each entry prematurely, leading it to prematurely delete the dictionary entry. So what are the possible causes of EOF making this mistake (or what is it that I'm doing that prompts EOF to make this mistake, if you prefer ;))? I guess that's what this whole thread has been about. Here's the list of things I know about:
- Don't set EO properties in the EO constructor -- use awakeFromInsertion(...) or awakeFromFetch(...) instead : I've examined each and every EO constructor in all my frameworks at least 4 times now. Most either don't exist, or just call super(), and the rest (one or two) only call super() and set a couple of non-modeled local attributes.
- Don't do anything to an EO before inserting it into an editing context. Always insert EOs into ECs immediately. See rule #1: I made a comprehensive list of all my EO classes (about 90) and then searched all applications and frameworks for "new X()" where X is the name of each EO. There are no results for any of my EOs anymore, because they all use EOUtilities.createAndInsertInstance. There are actually one or two places that I use introspection to create new EOs ,but in each of those places, they get inserted immediately after creation. Actually, this is something I've never heard discussed. Does EOF play nice with introspection? Maybe that is my problem. I will rewrite that code next...
- Don't modify any EO properties in validateFor...(...) methods. Doing this in validateValueForKey(...) is ok as Chuck Hill noted in the list.: There is only one validateFor method in all of the frameworks and applications:
public void validateForSave() throws NSValidation.ValidationException { super.validateForSave(); if ( supplier() == null ) { throw new NSValidation.ValidationException( "All inventory items must have a supplier" ); } } - If over-riding awakeFromInsertion(...), remember to call ther superclass implementation. Same with awakeFromFetch(...): This was the easiest one to verify. Searched all EOs, and for sure they all call super.awake...
- Don't change the behavior of methods that EOF uses. For example, do not override to-many relationships to return a sorted list of the related objects. Make another method to do this.: Verified that this cannot happen by commenting out all overridden methods in every EO I have, recompiling, rerunning the problematic code, and getting the same behavior
- Don't use mutable classes (e.g. NSMutableArray, NSMutableDictionary, any other class that can change internal state after creation) as attributes. If you want this effect, use immutable classes and provide cover methods to replace the immutable instance with an updated instance. You and EOF will be much, much, much happier: Definitely not doing this
- Locking problems: I turned on DebugGroupMultithreading in NSLog, and nothing happened. If I explicity comment out the code which locks my ECs, I get warnings all over the place, so it looks like my code is working in that regard.
Does anyone know of any other thing that causes EOF's snapshot counting to go screwy? You have something seriously bad in your application. I don't know what it is, yet. But there is something you are not telling us (not accusing you here, you undoubtedly are dismissing it as not relevant, I know that from personal experience). In my experience, EOF is very robust and dependable. As long as you don't mess with its head...
Well, I guess I can't complain too much. After all, they aren't charging anything for the product any more. And as long as there are good people willing to fill in the information gaps left by Apple about the product by sharing their experiences, I think it can continue to be a great way to develop web applications. For now, I'm going with the hack because I don't know what else to do. Thanks to all who continue to respond, and by all means, if anyone can think of anything else to try or anywhere else to look, let me know and I will try it/look there.
Mark |