[ZODB-Dev] Re: Ruby/Smalltalk OODB

Gary Poster gary at zope.com
Tue Jun 3 13:13:50 EDT 2008


Uh-oh, I'm implicated!

(see below)

On Jun 3, 2008, at 12:53 PM, Sean Allen wrote:
>>

...

>>
>>> If you do that in gemstone, there is only one copy of Order B, no  
>>> matter
>>> what variable in what dictionary you come at it from. And its drop  
>>> dead
>>> simple.
>>
>>> I looked at implementing that with zodb and moved along.
>>
>> I'm confused. This has been the way the ZODB worked for a long time,
>> unless I'm really missing something in your description.
>
> i tried to do this:
>
> create customer that has order
>
> so that i can have different extents type situations...
>
> store customer in one dictionary.
> store order in another.
>
> if i pulled the order back out from the order dictionary and  
> modified it
> then pulled the customer out, the customers order was no longer in  
> sync
> with what came out of the order dictionary.
>
> the reference was lost on serialization. original in memory objects  
> were fine,
> those that came back out from zodb werent.
>
> i'm going to quote the initial email i sent with the idea in general  
> and the followup i got
> and i then tried it out to make sure i hadnt asked the question  
> wrong, and yeah...
> what i wanted to do, wasnt easily done.
>
> the quotes:
>
>> The biggest concern I have is how do to the layout/storage so that  
>> this slightly contrived example works:
>>
>> Product has a brand.
>> There are many brands.
>>
>> How do I store so that I can find all products simply and all  
>> brands simply and also so that changes in a brand instance are  
>> reflected when
>> the product instance is deserialized. By 'simply' I mean that it  
>> doesnt really work on our end to have to walk all Products looking
>> for unique brands. Should just be able to go directly in and get  
>> said brands ( using keys() or similar call ).
>>
>> If I create 'brand' and 'product' as btrees, then if i do something  
>> like
>>
>> some_product.brand.name = 'something entirely different'
>>
>> and that brand already exists in 'brand', would it be updated? are  
>> references maintained in that fashion?
>> do we have to handle manually on update and creation?
>>
>> Note that we would just be using ZODB not Zope in this scenario.
>
> Back references are not maintained automatically.
>
> I'd identify two classic solutions to this sort of thing.
>
> One is to make a custom mapping (using a BTree as the inner data  
> structure) that maintains back-references when objects are placed in  
> them or removed.  zope.app(.container? .folder? I'd have to look)  
> has code that does this, along with firing events.  For simple  
> stories like the one you describe here, that's what I'd probably  
> recommend.  It works to the strengths of the ZODB, which  
> particularly shines in terms of readability when you just need to  
> walk a tree of attributes to get what you want.
>
> The other is to keep an external index, a la zc.extrinsicreference  
> or zc.relation.
>
> zc.extrinsicreference does not have too many dependencies beyond  
> ZODB, and as long as zope.app.keyreference doesn't drag much along  
> with it, might be usable as a library.  That said, it's also very  
> simple, and could be used as a model for you, even if you don't use  
> it directly.  It would also be a reasonable choice for a simple  
> situation like the one you describe.  It relies on events to update  
> its data structures.
>
> zc.relation an almost-released-revision of zc.relationship that  
> drastically reduces dependencies--actually, it has no additional  
> dependencies to ZODB, as you can see at http://svn.zope.org/zc.relation/trunk/setup.py?view=markup 
> .  It's also a bit overwhelming and low-level: see the README:http://svn.zope.org/zc.relation/trunk/src/zc/relation/README.txt?view=auto 
>  .  It doesn't hook anything up for you: you set the relationship  
> catalog up and you arrange for it to be updated, via events or  
> direct messages.  That said, if you need its power, it is well- 
> tested and would be a good choice for some jobs from at least some  
> perspectives (caveat read-or: I'm the author).

Now in the context of this discussion, I see that I misread you.  I  
apologize.

This works out of the box:

You have a Product class and a Brand class.  Both inherit from  
persistent.Persistent.

You have a persistent-aware mapping such as a BTree.

In the root of your ZODB, put two BTrees, one for your products and  
one for your brands.

Create some Brand instances and put them in the brand mapping.

Create some Product instances and put them in the product mapping.   
Assign some of the brands you have made as attributes of the products.

Now, product.brand.foo = 'bar' (in any thread or any ZEO client) will  
be changing the same effective object (let's call it a record) as the  
one in the brand mapping you have in the root of your db.

I believe that this is what you are talking about.

Again, I apologize for not reading your original question closely  
enough.

What you *can't* do out of the box is ask "hey, what products have an  
attribute that points to this brand?".  That's a back-reference, and  
that needs solutions like the ones to which I was referring.

Gary


More information about the ZODB-Dev mailing list