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 -~----------~----~----~----~------~----~------~--~---