oh man, i missed the biggest part of this one, after I noticed that  
you weren't doing anything to put the PhoneNumber in the session.    
Don't use Session.mapper.  That is the main problem you're having in  
this specific case.   Auto-adding free-standing objects to the session  
is a bad idea and I've downplayed the crap out of this legacy feature  
for years now.


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

>
> In the process of upgrading from 0.4 to 0.5 I've come across a
> troubling issue. With the following setup:
>
> ####################################################################################
>
> from sqlalchemy import Table, Column, Integer, String, MetaData,
> create_engine, ForeignKey
> from sqlalchemy.orm import relation, sessionmaker, scoped_session
>
> engine = create_engine('sqlite:///mystuff.sqlite', echo=True)
>
> Session = scoped_session(sessionmaker(autoflush=True,
> transactional=True, bind=engine))
> metadata = MetaData()
> mapper = Session.mapper
>
> time_zones = Table('time_zones', metadata,
>                 Column('id', Integer, primary_key=True),
>                 Column('name', String(35)))
>
> contacts = Table('contacts', metadata,
>                 Column('id', Integer, primary_key=True),
>                 Column('display_as', String(35)),
>                 Column('time_zone_id', Integer, ForeignKey
> ('time_zones.id')))
>
> phone_numbers = Table('phone_numbers', metadata,
>                 Column('id', Integer, primary_key=True),
>                 Column('number', String(35)),
>                 Column('contact_id', Integer, ForeignKey
> ('contacts.id')))
>
> class TimeZone(object): pass
> class Contact(object): pass
> class PhoneNumber(object): pass
>
> mapper(TimeZone, time_zones)
> mapper(Contact, contacts, properties={
>    'time_zone': relation(TimeZone, backref='contacts'),
>    'phone_numbers': relation(PhoneNumber, backref='contact',
> cascade='all, delete-orphan')
> })
> mapper(PhoneNumber, phone_numbers)
>
> metadata.create_all(bind=engine)
>
> ##############################################################################
>
> Under 0.4 the following code executes fine:
>
>
> ############
>
> c = Contact(display_as='Fake, User')
> c.time_zone = TimeZone.query.filter_by(name='Africa/Algiers').first()
> ph = PhoneNumber(full='1234567890')
> c.phone_numbers.append(ph)
> Session.commit()
>
> ############
>
> 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.
>
> Thank you for the assistance
> -Brad
>
>
> Below is the full echo output of 0.4 and 0.5
>
> 0.4.8dev_r5095:
> 2009-07-02 18:51:17,391 INFO sqlalchemy.engine.base.Engine.0x..70
> BEGIN
> 2009-07-02 18:51:17,391 INFO sqlalchemy.engine.base.Engine.0x..70
> INSERT INTO contacts (display_as, time_zone_id) VALUES (?, ?)
> 2009-07-02 18:51:17,391 INFO sqlalchemy.engine.base.Engine.0x..70
> ['Fake, User', None]
> 2009-07-02 18:51:17,391 INFO sqlalchemy.engine.base.Engine.0x..70
> SELECT time_zones.id AS time_zones_id, time_zones.name AS
> time_zones_name FROM time_zones WHERE time_zones.name = ? ORDER BY
> time_zones.oid LIMIT 1 OFFSET 0
> 2009-07-02 18:51:17,391 INFO sqlalchemy.engine.base.Engine.0x..70
> ['Africa/Algiers']
> 2009-07-02 18:51:17,407 INFO sqlalchemy.engine.base.Engine.0x..70
> SELECT phone_numbers.id AS phone_numbers_id, phone_numbers.number AS
> phone_numbers_number, phone_numbers.contact_id AS
> phone_numbers_contact_id FROM phone_numbers WHERE
> phone_numbers.contact_id = ? ORDER BY phone_numbers.oid
> 2009-07-02 18:51:17,407 INFO sqlalchemy.engine.base.Engine.0x..70 [4]
> 2009-07-02 18:51:17,407 INFO sqlalchemy.engine.base.Engine.0x..70
> INSERT INTO phone_numbers (number, contact_id) VALUES (?, ?)
> 2009-07-02 18:51:17,407 INFO sqlalchemy.engine.base.Engine.0x..70
> [None, 4]
> 2009-07-02 18:51:17,407 INFO sqlalchemy.engine.base.Engine.0x..70
> COMMIT
>
>
>
>
> 0.5.4p2:
> sa_test.py:8: SADeprecationWarning: The 'transactional' argument to
> sessionmaker() is deprecated; use autocommit=True|False instead.
>  Session = scoped_session(sessionmaker(autoflush=True,
> transactional=True, bind=engine))
> 2009-07-02 18:54:41,658 INFO sqlalchemy.engine.base.Engine.0x...2f30
> PRAGMA table_info("time_zones")
> 2009-07-02 18:54:41,658 INFO sqlalchemy.engine.base.Engine.0x...2f30
> ()
> 2009-07-02 18:54:41,658 INFO sqlalchemy.engine.base.Engine.0x...2f30
> PRAGMA table_info("contacts")
> 2009-07-02 18:54:41,658 INFO sqlalchemy.engine.base.Engine.0x...2f30
> ()
> 2009-07-02 18:54:41,658 INFO sqlalchemy.engine.base.Engine.0x...2f30
> PRAGMA table_info("phone_numbers")
> 2009-07-02 18:54:41,658 INFO sqlalchemy.engine.base.Engine.0x...2f30
> ()
> 2009-07-02 18:54:41,658 INFO sqlalchemy.engine.base.Engine.0x...2f30
> BEGIN
> 2009-07-02 18:54:41,658 INFO sqlalchemy.engine.base.Engine.0x...2f30
> INSERT INTO contacts (display_as, time_zone_id) VALUES (?, ?)
> 2009-07-02 18:54:41,658 INFO sqlalchemy.engine.base.Engine.0x...2f30
> ['Fake, User', None]
> 2009-07-02 18:54:41,674 INFO sqlalchemy.engine.base.Engine.0x...2f30
> SELECT time_zones.id AS time_zones_id, time_zones.name AS
> time_zones_name FROM time_zones WHERE time_zones.name = ? LIMIT 1
> OFFSET 0
> 2009-07-02 18:54:41,674 INFO sqlalchemy.engine.base.Engine.0x...2f30
> ['Africa/Algiers']
> Traceback (most recent call last):
>  File "sa_test.py", line 47, in <module>
>    c.phone_numbers.append(ph)
>  File "c:\program files\python\lib\site-packages\sqlalchemy-0.5.4p2-
> py2.5.egg\sqlalchemy\orm\attributes.py", line 158,
> in __get__
>    return self.impl.get(instance_state(instance), instance_dict
> (instance))
>  File "c:\program files\python\lib\site-packages\sqlalchemy-0.5.4p2-
> py2.5.egg\sqlalchemy\orm\attributes.py", line 374,
> in get
>    value = callable_()
>  File "c:\program files\python\lib\site-packages\sqlalchemy-0.5.4p2-
> py2.5.egg\sqlalchemy\orm\strategies.py", line 568,
> in __call__
>    result = q.all()
>  File "c:\program files\python\lib\site-packages\sqlalchemy-0.5.4p2-
> py2.5.egg\sqlalchemy\orm\query.py", line 1193, in a
> ll
>    return list(self)
>  File "c:\program files\python\lib\site-packages\sqlalchemy-0.5.4p2-
> py2.5.egg\sqlalchemy\orm\query.py", line 1286, in _
> _iter__
>    self.session._autoflush()
>  File "c:\program files\python\lib\site-packages\sqlalchemy-0.5.4p2-
> py2.5.egg\sqlalchemy\orm\session.py", line 899, in
> _autoflush
>    self.flush()
>  File "c:\program files\python\lib\site-packages\sqlalchemy-0.5.4p2-
> py2.5.egg\sqlalchemy\orm\session.py", line 1354, in
> flush
>    self._flush(objects)
>  File "c:\program files\python\lib\site-packages\sqlalchemy-0.5.4p2-
> py2.5.egg\sqlalchemy\orm\session.py", line 1414, in
> _flush
>    mapperutil.state_str(state), path))
> sqlalchemy.orm.exc.FlushError: Instance <PhoneNumber at 0xf8ae30> is
> an unsaved, pending instance and is an orphan (is n
> ot attached to any parent 'Contact' instance via that classes'
> 'phone_numbers' attribute)
> >


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