Search code examples
pythonzodb

ZODB not able to commit


I am using ZODB first time. Just trying to commit the data with FileStorage. But when I do the same script second time I am not able to commit the new object. Here is my script

from ZODB import FileStorage,DB
import transaction    
storage = FileStorage.FileStorage('/tmp/test.fs')
db = DB(storage)
conn = db.open()
root = conn.root()
#root['layer']={}
root['layer']['2b']={"id":'2b','name':'some name'}
transaction.commit()
conn.close()
db.close()
storage.close()

when I repeat the code once again, with just changing the id root['layer']['2c'] and come out of the python, the second time object is not getting committed. I only have first object only. What could be the reason.


Solution

  • The ZODB persistence layer detects changes by hooking into the python __setattr__ hook, marking the persistent object as changed every time you set an attribute.

    But if you use a primitive mutable object like a python dictionary, then there is no way for the persistence machinery to detect the changes, as there is no attribute being written. You have three options to work around this:

    Use a persistent mapping

    The persistent package includes a persistent mapping class, which is basically a python dictionary implementation that is persistent and detects changes directly by hooking into __setitem__ and other mapping hooks. The root object in your example is basically a persistent mapping.

    To use, just replace all dictionaries with persistent mappings:

    from persistent.mapping import PersistentMapping
    root['layer'] = PersistentMapping()
    

    Force a change detection by triggering the hook

    You could just set the key again, or on a persistent object, set the attribute again to force the object to be changed:

    root['layer'] = root['layer']
    

    Flag the persistent object as changed

    You can set the _p_changed flag on the nearest persistent object. Your root object is the only persistent object you have, everything else is python dictionaries, so you need to flag that as changed:

    root._p_changed = 1