[ZODB-Dev] Storing Persistent Objects with Persistent Objects asattributes of the Parent PO

Tim Peters tim at zope.com
Mon Jun 7 23:41:28 EDT 2004


[Patrick Hampton]
> import ZODB
> import Persistence 
>import BTrees
>
> strg = ZODB.FileStorage.FileStorage("/tmp/temp.fs")
> db = ZODB.DB(strg)
> conn = db.open()
> root = conn.root()
>
> root['games'] = BTrees.OOBTree.OOBTree()
> root['players'] = BTrees.OOBTree.OOBTree()
>
> class Game(Persistence.Persistent):
>     def __init__(self):
>         self.name = ''
>         self.gamemaster = None
>         self.players = []
>
> class Player(Persistence.Persistent):
>     def __init__(self):
>         self.name = ''
>         self.address = ['', '', '', '']
>         self.phone = ''
>         self.email = ''
>         self.password = ''
>
> player = Player() player.name = 'Player 1'
>
> game = Game()
> game.name = 'Game 1'
> game.gamemaster = player
>
> root['players'][player.name] = player
> root['games'][game.name] = game
> get_transaction().commit()
>
> ---
>
> When the commit happens does the player object get written into the games
> database with the game object or does a reference get written into the
> game object?

Thanks!  That makes the question very clear -- even to me <wink>.

I'll answer obliquely, but (I hope) more helpfully:  every revision of every
persistent object in a ZODB database is stored uniquely within the database.
So the current revision of the persistent object "player" is stored exactly
once, and no matter how often it's referenced or by how many other
persistent objects.

If you run fsdump.py over the FileStorage created by the program above, you
should see something like this:

Trans #00000 tid=0355a4021543db66 time=2004-06-08 03:14:04.984000 offset=52
        status=' ' user= description=initial database creation
  data #00000 oid=0000000000000000 class=Persistence.PersistentMapping

Trans #00001 tid=0355a40248323e88 time=2004-06-08 03:14:16.921000 offset=184
        status=' ' user= description=
  data #00000 oid=0000000000000000 class=Persistence.PersistentMapping
  data #00001 oid=0000000000000002 class=BTrees.OOBTree.OOBTree
  data #00002 oid=0000000000000003 class=__main__.Game
  data #00003 oid=0000000000000004 class=__main__.Player
  data #00004 oid=0000000000000001 class=BTrees.OOBTree.OOBTree

The first transaction was done for you "by magic", and created the root
object.  The second transaction is the one you did:  it wrote a new revision
of the root object (oid 0), and introduced two OOBTrees, a Game instance,
and a Player instance.  Your Player instance has oid (persistent object id)
3.  Anything anywhere in the database referencing this Player instance will
do so indirectly, via its oid.

If you run this program now:

import Persistence
import BTrees.OOBTree
import ZODB.FileStorage
strg = ZODB.FileStorage.FileStorage("/tmp/temp.fs")
db = ZODB.DB(strg)
conn = db.open()
root = conn.root()

... the Game and Player classes  ...

game = root['games']['Game 1']
p = game.gamemaster
print p._p_changed
print p.name
print p._p_changed


it prints


None
Player 1
0


That means p is a ghost as soon as it's fetched from game.gamemaster, which
means it's a so-far unmaterialized reference back to the database.  Printing
p.name forces it to get loaded from the database (in order to look up the
name attribute), and then p._p_changed becomes 0 (meaning it's now a
materialized object, and hasn't been changed since it was loaded from the
database; p._p_changed will become 1 if you modify this player instance).




More information about the ZODB-Dev mailing list