Re: Shared EC woes (was: Flattened one-side M:N fails wildly with SharedEC)
Re: Shared EC woes (was: Flattened one-side M:N fails wildly with SharedEC)
- Subject: Re: Shared EC woes (was: Flattened one-side M:N fails wildly with SharedEC)
- From: "ocs@ocs" <email@hidden>
- Date: Tue, 02 Oct 2018 12:51:17 +0200
Chuck,
> On 2 Oct 2018, at 8:10 AM, Chuck Hill <email@hidden> wrote:
> The other case though is weird. You might recall that my code
> - first does some special initialisations without a SEC (all the ECs I use
> has their SEC immediately upon creation set to nulls)
> - when done, I change the connection dictionary, re-connect using
> EODatabaseContext.forceConnectionWithModel, and run on normally with SECs.
>
> The problem is that during the special init code I happen to need a DBC; and
> it seems that the code
>
> def
> ctxt=ERXEOAccessUtilities.databaseContextForEntityNamed(ec.rootObjectStore(),someEntity.name)
>
> always initialises the default SEC and loads the shared EOs into it —
> regardless the fact that the ec does not have a SEC at all.
>
> I think the author of this may have not quite understood what setting the ec
> SEC to null does. It does not prevent SEC creation or loading, it just
> affects that particular EC and prevents it from getting/seeing objects in the
> SEC. So you can fetch shared objects into it, edit them and save them.
Quite, I see. Nevertheless, it would seem (perhaps mistakenly) to me that the
workflow
- connect to the database in a special way
- initialise without a SEC; this might change objects which normally go to SEC;
- re-connect to the database normally
- initialise and load and use SEC, as usual
is not completely crazy and makes sense?
Nevertheless, unless „re-connect“ includes restarting the application, I found
no way to achieve that :(
> Note that the call to ERXEOAccessUtilities.databaseContextForEntityNamed
> does not actually take the EC, it takes the root object store (aka
> EOObjectStoreCoordinator in most cases). So that ec.sharedEditingContext()
> == null is wholly irrelevant.
Quite; but originally, I (definitely mistakenly) though that SEC is initialised
and loaded on-demand only when for the first time touched through a normal EC
which contain it.
Actually, to work around this, I've tried to
- go through my model, (store and) remove all the
sharedObjectFetchSpecificationNames
- connect in a special way, do the initialisation
- restore all the sharedObjectFetchSpecificationNames
- re-connect etc.
Alas, this way, SEC gets never initialised/loaded.
> Subsequently, I change (in the EC without a SEC) some shared EOs. The
> documentation says that SEC would observe such changes and would refetch
> those shared EOs into a SEC; well, it does, but not when they happen, nor
> when the EC is saved, nor when it is unlocked — far as I was able to find, it
> happens only when the EO in the SEC is touched (i.e., its attribute is read).
>
> Your apps change the shared Eos when they launch and save them? Every time?
> That seems… counter intuitive.
My app contains plists which say how (some of) the shared EOs should look like.
Upon launching, the special-init-time, it synchronises the database with these
plists, so that they really do.
Normally, it would mean the shared EOs gets changed only when the application
itself (its plists) change, e.g., upon a new release with new features. When
testing though, I enforce this change every time, so that I know the
synchronisation works properly and am not surprised when deployed and the app
changes the next year :)
> Without looking, I’d interpret “that SEC would observe such change” as it
> will refault the shared objects when it gets the ObjectChangedInObjectStore
> notification. So the update to new values would naturally happen when
> willRead() is called on a shared EO.
There's no problem in that. The problem is that this leads to initializeObject:
attempt to initialize object ... error :/
> If this does not happen, i.e., if the previously changed shared EO is not
> touched in the SEC, a first fetch into a normal EC (with SEC) whose fetch
> spec happens to include a changed shared EO crashes. In other words, it goes
> like this:
>
> (a) init-time, I am consistently using ECs with null SEC;
> (b) with one of those, I call databaseContextForEntityNamed, which
> initializes and populates the default SEC;
> (c) later, in the EC with null SEC, I fetch and change a couple of shared EOs
> (they do not get re-loaded in SEC!)
> (d) later, normal-run-time, I fetch objects into an EC with SEC; the fetch
> spec happens to fit some shared EOs...
>
> ... and it results in a EOEditingContext: initializeObject: attempt to
> initialize object ... that exists in a shared context via a non-shared
> context. [1]
>
> Do the editing contexts from a...c still exist at this time?
Probably not. With the Java GC thing one can't be sure; but all of them are
stored in local variables of methods which have finished long ago.
Hmm... I guess I could make my own EC subclass, override dispose, and log out.
Or perhaps I can set log4j.logger.er...something to get that for free?
> I have found that the culprit object is one of those changed in the step (c),
> and I have found that touching the shared EO in the SEC before the fetch
> helps: the shared EO gets re-loaded, and the fetch works as presumed
> (returning the shared EO in the SEC). Now, I do this:
>
> - whenever the SharedEditingContextInitializedObjectsNotification comes, I
> record the SEC;
> - after the shared EOs are changed (in an EC with null SEC) and saved, I go
> through all the SECs recorded; for each of them I get all its
> registeredObjects, and for each of them call eo.storedValueForKey(anyKey). If
> the object has been changed, this re-loads it in SEC, and subsequent fetching
> works properly.
>
> This seems to me extremely weird. Can you understand what the heck happens
> there and why?
>
> No, not with any certainty. It feels like an EOF bug. Your usage is
> probably different from most, so you may be the first to find this.
Actually, I feel I must be doing something wrong at my side. Or is really the
workflow
- do something which inits and loads SEC
- load a shared EO into an EC with null SEC, update it, save
- in a normal EC (with SEC), do a fetch whose fetchspec fits some shared EOs
that unique? That seems surprising.
Thanks a lot and all the best,
OC
>
> From: "email@hidden <mailto:email@hidden>" <email@hidden <mailto:email@hidden>>
> Date: Friday, September 28, 2018 at 6:56 PM
> To: Chuck Hill <email@hidden <mailto:email@hidden>>
> Cc: WebObjects-Dev Mailing List <email@hidden
> <mailto:email@hidden>>
> Subject: Shared EC woes (was: Flattened one-side M:N fails wildly with
> SharedEC)
>
> Chuck,
>
> well, so far, I have found two problems with SEC. One of them is boringly
> self-evident, but a hell to find&fix: very simply, my legacy code did contain
> something like
>
> Foo something() {
> ...
>
> EOUtilities.objectWithPrimaryKeyValue(this.editingContext(),'NonSharedFooEntity',pk)
> }
>
> Which, of course, if this was shared, loads the object into SEC, and hilarity
> ensues. I wonder how many similar traps there are in my legacy code...
>
> The other case though is weird. You might recall that my code
> - first does some special initialisations without a SEC (all the ECs I use
> has their SEC immediately upon creation set to nulls)
> - when done, I change the connection dictionary, re-connect using
> EODatabaseContext.forceConnectionWithModel, and run on normally with SECs.
>
> The problem is that during the special init code I happen to need a DBC; and
> it seems that the code
>
> def
> ctxt=ERXEOAccessUtilities.databaseContextForEntityNamed(ec.rootObjectStore(),someEntity.name)
>
> always initialises the default SEC and loads the shared EOs into it —
> regardless the fact that the ec does not have a SEC at all.
>
> Subsequently, I change (in the EC without a SEC) some shared EOs. The
> documentation says that SEC would observe such changes and would refetch
> those shared EOs into a SEC; well, it does, but not when they happen, nor
> when the EC is saved, nor when it is unlocked — far as I was able to find, it
> happens only when the EO in the SEC is touched (i.e., its attribute is read).
>
> If this does not happen, i.e., if the previously changed shared EO is not
> touched in the SEC, a first fetch into a normal EC (with SEC) whose fetch
> spec happens to include a changed shared EO crashes. In other words, it goes
> like this:
>
> (a) init-time, I am consistently using ECs with null SEC;
> (b) with one of those, I call databaseContextForEntityNamed, which
> initializes and populates the default SEC;
> (c) later, in the EC with null SEC, I fetch and change a couple of shared EOs
> (they do not get re-loaded in SEC!)
> (d) later, normal-run-time, I fetch objects into an EC with SEC; the fetch
> spec happens to fit some shared EOs...
>
> ... and it results in a EOEditingContext: initializeObject: attempt to
> initialize object ... that exists in a shared context via a non-shared
> context. [1]
>
> I have found that the culprit object is one of those changed in the step (c),
> and I have found that touching the shared EO in the SEC before the fetch
> helps: the shared EO gets re-loaded, and the fetch works as presumed
> (returning the shared EO in the SEC). Now, I do this:
>
> - whenever the SharedEditingContextInitializedObjectsNotification comes, I
> record the SEC;
> - after the shared EOs are changed (in an EC with null SEC) and saved, I go
> through all the SECs recorded; for each of them I get all its
> registeredObjects, and for each of them call eo.storedValueForKey(anyKey). If
> the object has been changed, this re-loads it in SEC, and subsequent fetching
> works properly.
>
> This seems to me extremely weird. Can you understand what the heck happens
> there and why?
>
> Thanks and all the best,
> OC
>
> [1] it looks like this: with fetch code like
>
> println "FETCH $ec SEC:$ec.sharedEditingContext
> RELS:${EOModelGroup.defaultGroup.entityNamed(fs.entityName).relationships}"
> found=ec.objectsWithFetchSpecification(fs)
> println "FETCH $ec SEC:$ec.sharedEditingContext got $found"
>
> it quite consistently crashes like this:
>
> FETCH er.extensions.eof.ERXEC@11a11fbb
> SEC:com.webobjects.eocontrol.EOSharedEditingContext@79c3f01f RELS:[]
> 9301 [WorkerThread5] INFO er.transaction.adaptor.Exceptions - Database
> Exception occured ...
> ... ...
> Caused by: java.lang.IllegalArgumentException: EOEditingContext:
> initializeObject: attempt to initialize object with global ID
> _EOIntegralKeyGlobalID[DBDFList (java.lang.Integer)100] that exists in a
> shared context via a non-shared context. The object model may have a
> relationship from a shared entity to a non-shared entity. Disable or remove
> the relationship from the model.
> at
> com.webobjects.eocontrol.EOEditingContext.initializeObject(EOEditingContext.java:3760)
> at er.extensions.eof.ERXEC.initializeObject(ERXEC.java:1237)
> at
> com.webobjects.eoaccess.EODatabaseChannel$_EODatabaseChannelFetchResult.initializeObjects(EODatabaseChannel.java:496)
> at
> com.webobjects.eoaccess.EODatabaseContext._objectsWithFetchSpecificationEditingContext(EODatabaseContext.java:3090)
> at
> com.webobjects.eoaccess.EODatabaseContext.objectsWithFetchSpecification(EODatabaseContext.java:3195)
> at
> com.webobjects.eocontrol.EOObjectStoreCoordinator.objectsWithFetchSpecification(EOObjectStoreCoordinator.java:488)
> at
> com.webobjects.eocontrol.EOEditingContext.objectsWithFetchSpecification(EOEditingContext.java:4069)
> at er.extensions.eof.ERXEC.objectsWithFetchSpecification(ERXEC.java:1307)
> at
> com.webobjects.eocontrol.EOEditingContext.objectsWithFetchSpecification(EOEditingContext.java:4444)
> at
> com.webobjects.eocontrol.EOEditingContext$objectsWithFetchSpecification$0.call(Unknown
> Source)
>
> if, though, I programmatically find the object which is to be fetched in the
> SEC and touch it like this:
>
> println "FETCH $ec SEC:$ec.sharedEditingContext
> RELS:${EOModelGroup.defaultGroup.entityNamed(fs.entityName).relationships}"
> ec.sharedEditingContext.registeredObjects.findAll {
> it.entityName==fs.entityName && fs.qualifier.evaluateWithObject(it) }.each {
> it.storedValueForKey('title') // sufficient to touch the thing to reload it
> in SEC; without it is never reloaded and causes the crash
> }
> found=ec.objectsWithFetchSpecification(fs)
>
> it never crashes; and, as soon as storedValueForKey is called, the object is
> re-loaded in the SEC. It is sufficient to out-comment the storedValueForKey
> to get the attempt to initialize object ... that exists in a shared context
> crash back. Far as the storedValueForKey is there, it does not crash.
>
>
> On 26. 9. 2018, at 7:12 PM, Chuck Hill <email@hidden
> <mailto:email@hidden>> wrote:
>
> Hi OC,
>
> No, no magic like that. At least not that I know of. Subclassing
> EOEditingContext, EOSharedEditingContext, maybe EODatabaseContext is probably
> your best bet to pursue this.
>
> Chuck
>
> From: "ocs@ocs" <email@hidden <mailto:email@hidden>>
> Date: Wednesday, September 26, 2018 at 8:40 AM
> To: Chuck Hill <email@hidden <mailto:email@hidden>>
> Cc: WebObjects-Dev Mailing List <email@hidden
> <mailto:email@hidden>>
> Subject: Re: Flattened one-side M:N fails wildly with SharedEC
>
> Chuck,
>
>
>
> On 19 Sep 2018, at 9:57 PM, Chuck Hill <email@hidden
> <mailto:email@hidden>> wrote:
> Uh oh, the dreaded Schrödinger EOF behaviour! Have you figured anything out?
>
> Alas, nope. The darned “The shared context recently initialized the object
> ...” thing occurs intermittently, and whenever I add extra logs to find the
> culprit, it disappears. To occur again the next day or the next week.
>
> Is there some trick to set up something somewhere so that
>
> (a) until the SEC tries to load a non-shared object, all runs normally, there
> are no extra logs nor big performance delays,
> (b) but, as soon as that happens, I get a very detailed log which would not
> only say which object is the culprit, but also the reason why has it been
> loaded into SEC, through which relationship, etc.?
>
> Thanks and all the best,
> OC
>
>
>
>
> From: "ocs@ocs" <email@hidden <mailto:email@hidden>>
> Date: Wednesday, August 29, 2018 at 12:38 PM
> To: Chuck Hill <email@hidden <mailto:email@hidden>>
> Cc: WebObjects-Dev Mailing List <email@hidden
> <mailto:email@hidden>>
> Subject: Re: Flattened one-side M:N fails wildly with SharedEC
>
> Darn...
>
>
>
>
> might have been caused by something else, which is just loosely related to
> the change — a log in the code for all I know; the Schrödinger EOF behaviour
> did bit me once or twice already
>
> ... I should have not written this part!
>
> I have seen the blasted “The shared context recently initialized the object
> ...” thing again.
>
> Added log to pursue it. It did not happen.
>
> Removed the log. It still did not happen.
>
> Curiouser and curiouser...
>
> Thanks and all the best,
> OC
>
>
>
>
> On 29 Aug 2018, at 7:49 PM, ocs@ocs <email@hidden <mailto:email@hidden>> wrote:
>
> Chuck,
>
>
>
>
> On 29 Aug 2018, at 7:14 PM, Chuck Hill <email@hidden
> <mailto:email@hidden>> wrote:
> I am not sure that I am following this correctly. The rule is that no Shared
> EO should have a relationship to anything that is not also a Shared EO.
>
> The opposite direction (from normal EC to SEC) should be all right though,
> should it not?
>
>
>
>
> That includes the tables not materialized into an EO.
>
> I do not follow here.
>
> My shared entity S had no relationship to non-shared ones at all. Not even an
> empty one; none altogether.
>
> My non-shared entity A has a to-many relationship “aaa” to a non-shared B; B
> has a to-one relationship “bbb” to shared S (no inverse here). B is the M:N
> table, i.e., it contains just the A's and S's PKs.
>
> When non-shared A contained a flattened relationship “ddd” defined as
> “aaa.bbb”, EOF kept trying to load A into SEC (which naturally failed).
>
> I've removed the flattened “ddd” from the model (no other change there), and
> implemented its behaviour manually (in A just getting “aaa” programmatically,
> and then for all its objects collecting their “bbb”'s), and the problem
> disappeared; A has been no more loaded to SEC.
>
> Of course, it might have been caused by something else, which is just loosely
> related to the change — a log in the code for all I know; the Schrödinger EOF
> behaviour did bit me once or twice already :) it does seem very weird to me
> that the flattened thing should be the culprit; that's why I am asking
> whether such kind of behaviour is to be expected, or whether I should try to
> hunt for the culprit elsewhere.
>
> Thanks and all the best,
> OC
>
>
>
>
>
> From: Webobjects-dev
> <webobjects-dev-bounces+chill=email@hidden
> <mailto:webobjects-dev-bounces+chill=email@hidden>> on
> behalf of "ocs@ocs" <email@hidden <mailto:email@hidden>>
> Date: Wednesday, August 29, 2018 at 8:28 AM
> To: WebObjects-Dev Mailing List <email@hidden
> <mailto:email@hidden>>
> Subject: Flattened one-side M:N fails wildly with SharedEC
>
> Hi there,
>
> just have bumped into another weird (at least to me) behaviour.
>
> In my model, there used to be a very standard M:N relationship, which
> exploits an “invisible” intermediate table, flattened “direct” relationships
> ad both sides.
>
> One of the sides lately went to the sharedEC; thus I made sure to delete this
> side's flattened relationship. The other side and the intermediate table both
> stay outside of the sharedEC, so I thought that is all right.
>
> It failed miserably with “The shared context recently initialized the object
> <non-shared-one> which is already registered in this context yadda yadda”,
> i.e., EOF for some godforsaken reason kept loading the non-shared object (the
> one whose relationship remained intanct) into SEC along with the shared one
> (whose relationship were removed all right, no traces remained; I have
> checked about zillion times).
>
> Out of desperation, I have just tried to remov the flattened relationship
> from the non-shared side, exposing instead the intermediate table, and
> replacing the flattened relationship by something like
>
> ===
> List availablePrototypes { // this is how the original flattened rel has
> been named
> def mn=this.db_Prototype_DataBlock // 1:N relationship to the
> intermediate table, exposed
> mn.collect {
> it.valueForKey('prototype') // N:1 relationship from the inmdt
> table to the shared object
> }
> }
> ===
>
> and it seems to work all right :-O So, it looks like the culprit was the
> existence of the flattened rel with definiton
> “db_Prototype_DataBlock.prototype” at the non-shared side.
>
> Is that the intended behaviour? Seems pretty weird to me, but as always, I
> might be overlooking something of importance. Or should that work even with
> the flattened relationship, and the problems mean I must have done something
> wrong elsewhere?
>
> Thanks and all the best,
> OC
>
> _______________________________________________
> Do not post admin requests to the list. They will be ignored.
> Webobjects-dev mailing list (email@hidden
> <mailto:email@hidden>)
> Help/Unsubscribe/Update your Subscription:
>
> This email sent to email@hidden <mailto:email@hidden>
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Webobjects-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden