On Oct 22, 1:25 pm, Steve Harris <[EMAIL PROTECTED]> wrote:
>
> If however the p.children attribute is forced to load before the final
> line, by either eagerloading "children" attribute in the query for p,
> or by just printing p.children, then there is no error.  Also no error
> of course if the classes/tables are modified so that there is no
> second parent at all.  I don't see how the presence of the second
> parent in the design seems to cause the main parent not to adopt the
> child.  

The only reason "p2" has any interaction here is because SQLA's
default "cascade" rules indicate that Child should be automatically
added to the session in which "p2" is already a member.   In this
case, the addition is premature since the Child object is not fully
assembled for an INSERT, yet the session can flush at any time it is
asked to retrieve state due to autoflush.

Any Query issued is going to autoflush the session.    A lazy load
qualifies as a query which should autoflush.  The idea of autoflush is
that anytime you access an attribute which has no loaded state,
SQLAlchemy first synchronizes all of its pending changes with the
database, then loads the state.  Otherwise, the SQL would be issued, a
blank attribute or collection is populated, and a flush() later on may
in fact set up state within the transaction that would have been
populated on that load; now you have an attribute that is not
synchronized with the current transactional state.   Its not that big
a deal to work without the autoflush feature though; it was only
introduced in SQLA 0.4 and people didn't have too much trouble before
it was available, except that they were annoyed about the need to
issue flush() all the time.

Here is a simplified view of what's happening, without any second
parent relation:

from sqlalchemy.orm import *
from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base

engine = create_engine('sqlite:///:memory:')
DeclarativeBase = declarative_base()
session = sessionmaker(engine)()

class Parent(DeclarativeBase):
     __tablename__ = 'parent'

     id = Column(Integer, Sequence('S_PARENT', optional=True),
autoincrement=True, primary_key=True)
     name = Column(Unicode(100), unique=True)

class Child(DeclarativeBase):
     __tablename__ = 'child'

     id = Column(Integer, Sequence('S_CHILD', optional=True),
autoincrement=True, primary_key=True)
     name = Column(Unicode(100), nullable=False)
     parent_id = Column(Integer, ForeignKey("parent.id",
ondelete="CASCADE"), nullable=False)
     parent = relation(Parent, backref=backref('children',
order_by=id))

DeclarativeBase.metadata.create_all(engine)

p = Parent(name = u'tmp')
session.save(p)
# autoflushes, so "p" now is persistent
p = session.query(Parent).filter(Parent.name == u'tmp').one()
c = Child(name=u'the child')

# the association of "c" to "p2" has the effect of "c" being added to
the session
session.save(c)

# access p.children - this has not been loaded yet and may have state
# in the DB.  autoflush occurs, flushes "c" which is not fully
initialized
children = p.children

> I don't really understand the connection to autoflushing that
> the trac item mentioned, either (and I don't have an autoflush
> attribute on my scoped session, it appears).

To get at the autoflush attribute, access the actual session from the
scoped session:

session = my_scoped_session()
session.autoflush= False

> Thoughts?  Is this the way it should be?

SQLA's default cascade is set up for convenience in the usual case.
In this case its getting you into trouble so it makes sense that you'd
just need to more explicitly control the point at which "c" is added
to the session - this is the last workaround I provided.
--~--~---------~--~----~------------~-------~--~----~
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 [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to