wait...that's where you lose me. In this condition where user's
changed someobject.some_related_id, then as soon as that is flushed,
someobject.some_related by definition is no longer going to be the
object we get with the currently committed id.... This is circling
back to the automatic expiration of relationships dilemma. it seems
we are purposefully giving them the wrong object. Directly after the
flush, were we to query that same relationship, it would return a
different object/collection.
I believe that is the other reason I needed to abandon trusting the
relationship when within a flush. I think I recall this exact problem
occurring to me. The id had changed and anywhere else within
SQLAlchemy land (that isn't in a flush), I could trust the
relationship to bring back the correct object given the current state
of the id. However, in that case (inside a flush) it was bringing
back the wrong object (the one inconsistent with the current id) so
inspecting that related object's values would give me the wrong
answer.
You sure this logic (and therefore also test cases) aren't wrong?
Here is the script output for a demonstration. I can't imagine this
being the behavior we want, is it?
******* Before move: rockid=[1] rock object: <Rock: id=[1]>
******* During flush: rockid=[0] rock object: <Rock: id=[1]>
******* After flush: rockid=[0] rock object: <Rock: id=[0]>
=========================================================================
from sqlalchemy import *
from sqlalchemy.orm import *
engine = create_engine('sqlite:///', echo=False)
metadata = MetaData(engine)
Session = sessionmaker(bind=engine)
rocks_table = Table("rocks", metadata,
Column("id", Integer, primary_key=True),
)
bugs_table = Table("bugs", metadata,
Column("id", Integer, primary_key=True),
Column("rockid", Integer, ForeignKey('rocks.id'),),
)
class Rock(object):
def __repr__(self):
return '<Rock: id=[%s]>' % self.__dict__.get('id')
class Bug(object):
def __repr__(self):
return '<Bug: id=[%s]>' % self.__dict__.get('id')
def printstate(self, msg):
print "\n******* %s: rockid=[%s] rock object: %r\n" % (msg,
self.__dict__.get('rockid'), self.rock)
class BugAgent(MapperExtension):
def before_update(self, mapper, connection, instance):
instance.printstate("During flush")
session.expire(instance, ['rock'])
mapper(Rock, rocks_table,
properties={'bugs': relationship(Bug,
cascade='all,delete-orphan',
single_parent=True,
lazy=False,
backref='rock')
})
mapper(Bug, bugs_table, extension=BugAgent(),
allow_partial_pks=False)
metadata.create_all()
session = Session()
# add a rock and bug
rock=Rock()
rock.id = 0
bug=Bug()
bug.id = 0
rock.bugs.append(bug)
session.add(rock)
# add another rock and bug
rock=Rock()
rock.id = 1
bug=Bug()
bug.id = 1
rock.bugs.append(bug)
session.add(rock)
session.commit()
session.expunge_all()
# later... new session
session = Session()
b1 = session.query(Bug).get(1)
b1.printstate("Before move")
# Move bug to another rock...
b1.rockid = 0
session.expire(b1, ['rock'])
session.flush()
b1.printstate("After flush")
=========================================================================
--
You received this message because you are subscribed to the Google Groups
"sqlalchemy" group.
To post to this group, send email to [email protected].
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.