Re: [Modeling-users] Foreign Keys
Status: Abandoned
Brought to you by:
sbigaret
From: Sebastien B. <sbi...@us...> - 2003-07-21 22:26:20
|
Replying to my own post, I'd like to share some additional informations: I wrote: > Now back to your specific problem: based on your code, I assume you have > the following model: >=20 > master <--->> i18n (-> is to-one, ->> is to-many) >=20 > So you'll do something like this, assuming that the master entity's name > is 'Master' and the relationship' name i18n--->>master is: 'master' > and the inverse is 'i18ns': >=20 > >>> i18n =3D I18N() > >>> ec.insert(i18n) > >>> master=3Dec.faultForRawRow(masterSnapshot, 'Master') > >>> i18n.addObjectToBothSidesOfRelationshipWithKey(master, 'master') > >>> ec.saveChanges() >=20 > or its alternate equivalent: >=20 > >>> i18n =3D I18N() > >>> ec.insert(i18n) > >>> master=3Dec.faultForRawRow(masterSnapshot) > >>> master.addToI18ns(i18n) > >>> i18n.setMaster(master) > >>> ec.saveChanges() > > Naturally, this implies that the 'master' object is fetched and > initialized within the EditingContext. Each of these approaches triggers in fact two faults: 1. the fault for object 'master', which is fetched as soon as addToI18ns is called (triggered by self.willRead()), 2. the fault for master.i18ns (array), which is fetched as soon as addToI18ns() appends the new object to the array. In this particular situation, there is a third way of doing this. It should be considered as a 'hack' to be used in controlled situations (for example, in batches where you exactly know what has happened before), because of the limitations discussed below. However and given these restrictions, it can accelerate the change: >>> i18n =3D I18N() >>> ec.insert(i18n) >>> master=3Dec.faultForRawRow(masterSnapshot) >>> if master.isFault() and ec.parentObjectStore().__class__=3D=3DEditingCo= ntext: ... i18n.setMaster(master) ... else: ... i18n.addObjectToBothSidesOfRelationshipWithKey(master, 'master') >>> ec.saveChanges() What happens here? The difference here is that when most of your masters are faults, then you'll avoid to initialize both the masters and their i18ns. It works here because of two reasons: this is a toMany relationship, and we know from the model that the information used for both relationships 'master' and 'i18ns' is ultimately stored in the foreign key of table I18N, nothing more. When the master object is a fault, it's not initialized yet, and knowing that its relations are about to change does not add anything compare to: just wait until it's needed, where it will get its related objects, based on the information stored in the I18N's FK. (I hope I succeeded in making this clear) However, I strongly suggest not to remove the test 'if master.isFault()...', because if for some reasons the master object was already fetched (believe me, it can happen and surprise you in your own code ;) this would lead to an inconsistency in the graph of objects (i.e. master object's i18ns array not being updated where it should be) The second test checks that the ec is not nested (see http://modeling.sf.net/UserGuide/nested-ec-dev-hints.html). If it is nested, I suspect (even if I did not check it explicitely) that there are particular situations in which the parent's graph of objects could become inconsistent when the child save its changes. Last, it should *never* been used in a multi-threaded environment, because too much thing can happen between the moment where the changes are made and the time saveChanges() is called. All these precautions are what I previously called a "controlled environment". May I suggest that this gets somehow specifically documented in your code if you use this, so that anyone else working on your code does not get bitten by this in 2 years, 2 months or 2 days?-) (I initially wondered whether this should be shared after all, because of all this, but I think it might come in handy for particular situations, and that it cay also highlights some particular aspects of the framework). You can then verify that you won't get into trouble. For example, if you then trigger the two faults, master.geti18n() will contain the new one, as expected. -- S=E9bastien. |