[ZPatterns] _v_dm_ KeyError calling get_transaction().abort()

Itai Tavor itai@optusnet.com.au
Tue, 9 Oct 2001 12:08:28 +1000


Phillip J. Eby wrote:

>At 09:33 AM 10/9/01 +1000, Itai Tavor wrote:
>
>>Not quite sure what you mean by "get your self object again" - do 
>>you mean do self=self.getItem(self.id)? This trickery is a bit over 
>>my head...
>
>Just to explain more clearly what's going on, I thought I'd jump in 
>for a second...
>
>ZPatterns objects retrieved from a Rack are not guaranteed to remain 
>valid across transactional boundaries.  In particular, aborting a 
>transaction (even a subtransaction) guarantees that any references 
>you have to a DataSkin will be invalid.  You *must* re-retrieve the 
>object from the Rack, or, in the case of a non-rackmounted DataSkin, 
>re-retrieve it from its container.  My suggestion for the code would 
>be something like:
>
>id, DM = self.id, self._v_dm
>get_transaction().abort()
>self = DM.getItem(id)
>
>Thus, self is now a reference to an object in the *new* transaction 
>space.  It will have all its "magic" properly in place, where the 
>aborted object will not.
>
>Please note that if any other references to DataSkins which were 
>saved before the aborted transaction are used, they will also be 
>invalid and cause errors.
>
>Technically speaking, references should not be held even across a 
>subtransaction commit operation, but this doesn't usually cause many 
>problems in practice.  The only potential issue with a commit is 
>that the Rack's per-transaction cache will be cleared, so when using 
>virtual (e.g. SQL) objects, a post-commit retrieve might return an 
>object which is not the "same" object as the one you hold a 
>reference to.  This is only a problem if you do such a thing, of 
>course.

Thanks for the explanation. Until I find a better way to approach the 
whole problem, I'll use your code snippet.

>>Could you please describe how you would solve this problem? I'd 
>>really like to know if there is a better approach.
>>
>>Just to make sure you understood my problem correctly: The edit 
>>method modifies the object, and possibly modifies and creates other 
>>related objects, with values submitted in a form. If any of these 
>>actions cause errors, these are added to an 'errors' dictionary. I 
>>then roll back all the changes and display the errors by rendering 
>>the original form. The need to abort came from the fact that the 
>>form is rendered while the object is in its new, invalid state, 
>>because the changes have not been rolled back yet.
>
>Hm.  My usual approach to handling this is to just throw an error 
>when a problem is found, albeit a fancy error text explaining the 
>problem, and ask the user to press the back button to go back and 
>correct.

This is certainly the easiest way, but IMHO it's bad UI, for two 
reasons. First, all errors should appear at once. I don't want to 
make a user fix one error, submit the form, get a 2nd error, submit 
the form again... Second, it's much easier for a user to fix errors 
when she can see them highlighted in the actual form. My error 
handling would be a whole lot simpler if I didn't believe that it's 
important to provide this feature...


>However, I think the simple way to do what you want is probably just 
>to pre-render the form *before* you do the operations which might 
>cause errors.  If you get an error, just raise the pre-rendered 
>form.  Of course, it's more complex if you embed the error text 
>multiple places in the form...

Won't work because the form displays the error messages, so it can't 
be rendered before the error messages are collected...

Back to the drawing board. I wonder if the approach Steve hinted on 
might be more helpful for my requirements.
-- 
--
Itai Tavor                      -- "Je sautille, donc je suis."    --
itai@optusnet.com.au            --               - Kermit the Frog --
--                                                                 --
-- "If you haven't got your health, you haven't got anything"      --