[ZODB-Dev] Help: ZODB undo problem
Mike C. Fletcher
mcfletch@rogers.com
Tue, 18 Jun 2002 21:30:52 -0400
Thanks Shane and Christian,
Unfortunately, I am already using a sync, reset and _resetCache,
combination which was what got me from "no objects update" to "only
objects with explicit references fail to update". The code I'm
currently using does this:
undoInfo = self.database.undoInfo( 0, sys.maxint )
if undoInfo:
ID = undoInfo[0]['id']
self.database.undo(ID)
get_transaction().commit()
for item in APPLICATION.GetTables():
item._v_indices_initialised = 0
item.GetIndices()
self.connection.reset()
self.connection.sync()
self.connection._resetCache()
Given that this seems to be an "outside common experience" problem, I've
decided to implement (and am almost done integrating) database weakref
objects (option 2), and punt on trying to figure out why it's failing (I
want to ship this beta before Monday, and there's lots of other todo
items). I'm guessing it might be a problem with the
indexed-object-collection classes I'm using, though I don't see why
that's the case at the moment.
With the weakref class, I'm able to avoid the problems with the dialogs
holding objects, at the expense of explicitly coding every object to use
weak database references for all run-time references to objects in the
database (which is taking a while, but isn't killing me I suppose :o/ ).
For the curious, here's the weak reference class:
import weakref
def ref( object ):
if hasattr( object, '_p_oid'):
return DBObjectWeakRef( object )
else:
return weakref.ref( object )
class DBObjectWeakRef( object ):
"""Reference to a particular object in the database
Basically this is a weakref that tries to re-connect
when the original reference is cleaned up.
Note: assumes use in ConflictSolver, where APPLICATION
gives us a pointer to the application with the same
structure as the ConflictSolver application.
"""
def __init__( self, object ):
self.object = weakref.ref( object )
try:
self.oid = object._p_oid
except AttributeError:
raise TypeError( """Attempt to create a DBObjectWeakRef to
a non-database object %s"""%(repr(object)))
def __call__( self ):
"""We try to act like a weakreference as much as possible"""
object = self.object()
if object is not None:
return object
else:
return self.loadFromDatabase()
def loadFromDatabase( self ):
"""Attempt to load from database, storing a weakref if
successful"""
database = APPLICATION.database
if database:
try:
connection = APPLICATION.database.connection
if connection:
object = connection[ self.oid ]
if object is not None:
self.object = weakref.ref( object )
return object
except:
return None
return None
def __nonzero__( self ):
"""Test whether we're still valid"""
return self() is not None
With thanks to you both,
Mike
Christian Reis wrote:
...
> get_connection().sync() IIRC - have you tried it?
...
> Well, you have to call connection.sync() to do this manually. It was
> decided (IIRC) that updating all the objects automatically wouldn't be
> the Right Thing (tm) to do since it would break all the references the
> application held locally; it could elect to update them when it wanted.
...
> Well, we do undo in Stoq, using the ZODB, so I don't think it should be
> a problem. All you do is roll the transaction back and re-show the
> object.
>
> Take care,
> --
> Christian Reis, Senior Engineer, Async Open Source, Brazil.
> http://async.com.br/~kiko/ | [+55 16] 261 2331 | NMFL
...
_______________________________________
Mike C. Fletcher
http://members.rogers.com/mcfletch/