On Jul 2, 2009, at 7:21 PM, Brad Wells wrote:

>
> But under 0.5 I receive an orphaned object error (see below for full
> output). I understand that the TimeZone query causes a flush in
> between the creation of the Contact and of the PhoneNumber. Without
> the flush in between (if the TimeZone query line is removed) SA 0.5 is
> correctly able execute the sample script.
>
> As per this thread (http://groups.google.com/group/sqlalchemy/
> browse_thread/thread/6c71c61bc59223f?tvc=2) I see that a suggested
> remedy is to change the relation to cascade='all' rather than
> cascade='all, delete-orphan'.
> I would prefer not to do this as it really does make no sense in this
> case to have a PhoneNumber without a Contact. I could also set the
> relation via 'ph.contact = contact' but I would prefer to not have to
> comb all of our existing code for this new class of bug.
>
> What doesn't make sense to me is why 0.4 was able to correctly delay
> the insert of the new phone number record until after the query for
> the collection and now 0.5 can't.
>

its because accessing the lazy collection on c.phone_numbers doesn't  
trigger autoflush in 0.4, while it does in 0.5.  Below is a test case  
which fails only on 0.4 due to this behavior.  0.5 IMO is the one  
which is more "correct", but its an unfortunate feature since this is  
a frequent inconvenience.  The issue demonstrated below is probably  
not as common of a use case as that of just appending a non- 
orphanable, pending object to a collection.  But, an argument in favor  
of 0.5's behavior is that the orphan error, while inconvenient,  
complains loudly and is easily remedied (assuming one understands lazy  
collections and autoflush), whereas the failure in 0.4 is silent.

a possible workaround would be to make the autoflush on the relation()  
optional based on a configuration option, although that seems like yet  
another obscure flag nobody would ever find out about and it also  
dilutes the consistency of autoflush's behavior.

What I've advised to people in the past, and have also used myself, is  
to temporarily disable autoflush on the session during code sections  
that a lot of object manipulation is to occur, such as a form-to-model  
population method in a web app.   I made a decorator which  
accomplishes this and it also fits nicely into a "with:" construct  
(i.e. with no_autoflush():)".

using a "dynamic" relation (i.e. lazy="dynamic") would also alleviate  
this problem since those collections don't request data unless they  
are iterated.   "dynamic" relations are the style of collection most  
other Python ORMs use in all cases.

from sqlalchemy import *
from sqlalchemy.orm import *

engine = create_engine('sqlite:///', echo=True)

metadata = MetaData()
users = Table('users', metadata,
       Column('id', Integer, primary_key=True),
       Column('name', String(30), nullable=False),
       )

addresses = Table('addresses', metadata,
       Column('id', Integer, primary_key=True),
       Column('user_id', None, ForeignKey('users.id')),
       Column('email_address', String(50), nullable=False))

metadata.create_all(engine)
engine.execute(users.insert(),dict(id=8, name='ed'))

engine.execute(addresses.insert(),
     [dict(id=x, user_id=y, email_address=z) for x, y, z in [
     (2, 8, "e...@wood.com"),
     (3, 8, "e...@bettyboop.com"),
     (4, 8, "e...@lala.com"),
     ]])

class User(object):
     pass
class Address(object):
     pass

mapper(User, users, properties={
     'addresses':relation(Address, order_by=addresses.c.email_address)
})
mapper(Address, addresses)

s = create_session(autoflush=True, transactional=True, bind=engine)

u = s.query(User).get(8)

ad2 = s.query(Address).get(2)
ad2.email_address = 'aaaaa'

assert [a.email_address for a in u.addresses] == ['aaaaa', 'e...@bettyboop.com 
', 'e...@lala.com']


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to