On Mar 25, 2014, at 12:16 PM, Philip Scott <safetyfirstp...@gmail.com> wrote:
> I understand, I had a feeling it would be something like that. Don't worry, I > can work around it by using a subqueryload() instead (which I guess fixes it > by changing the order things are loaded?) I'd have to look into it, I'm not sure why offhand. > > Thank you very much for taking the time to answer; still loving SQLAlchemy! > > > On Tue, Mar 25, 2014 at 1:06 PM, Michael Bayer <mike...@zzzcomputing.com> > wrote: > > On Mar 25, 2014, at 7:48 AM, Philip Scott <safetyfirstp...@gmail.com> wrote: > >> Ah, so, it turns out to be more subtle than I first thought. It took me >> quite a while to narrow it down to an easily reproducible case. To trigger >> the behavior you need to be: joinedloading() along a backref, and also I >> think it matters that I am joining back onto the same table and returning a >> bunch of objects. Quite a corner case I think. >> >> This code demonstrates the behavior - it issues a second query in the for >> loop for the 'A' which has no child. > > > this is very difficult to resolve and it may have been something I've said > was unfixable in the past. The "a2" object here is loaded in two different > contexts, one is as the joined loaded child of a1, the other as a first class > result. Because when the query orders by a1, a2, we hit a1 first, a2 is > necessarily loaded as the child of a1. The joined loading only goes one > level deep, that is, it doesn't load the children of children, unless you > told it to by saying joinedload("child").joinedload("child"). So a2.child's > loader is declared as "not loaded". then on the next row it comes in as a > first class result, but the a2 object we get there is only an identity map > lookup - this object is already loaded. > > Adjusting this behavior would require the loading logic figure out > mid-results that the context for a particular object is changing. pretty > complicated. > > >> >> >> from sqlalchemy import * >> from sqlalchemy.orm import * >> from sqlalchemy.ext.declarative import declarative_base >> >> Base = declarative_base() >> >> class A(Base): >> __tablename__ = 'a' >> >> id = Column(Integer, primary_key=True) >> >> join_table = Table('parent_child', Base.metadata, >> Column('id_a', ForeignKey('a.id')), >> Column('id_b', ForeignKey('a.id'))) >> >> parent = relationship("A", >> secondary=join_table, >> primaryjoin = (id == join_table.c.id_a), >> secondaryjoin = (id == join_table.c.id_b), >> uselist=False, >> backref=backref("child", uselist=False)) >> >> e = create_engine("sqlite://", echo=True) >> Base.metadata.create_all(e) >> >> sess = Session(e) >> a1 = A() >> a2 = A(parent=a1) >> sess.add(a1) >> sess.add(a2) >> sess.commit() >> sess.close() >> >> results = sess.query(A).options(joinedload("child")).all() >> print "----" >> for a in results: >> print a.child is None >> >> >> >> >> >> On Mon, Mar 24, 2014 at 8:34 PM, Michael Bayer <mike...@zzzcomputing.com> >> wrote: >> >> On Mar 24, 2014, at 2:09 PM, Philip Scott <safetyfirstp...@gmail.com> wrote: >> >> > >> > Is this a bug, or perhaps some expected side effect of the joined load? >> >> seemed like something that might be possible but the scalar loader is >> initializing the attribute to None to start with, here's a simple test that >> doesn't show your behavior, so see if you can just modify this one to show >> what you are seeing. note we only need to see that 'bs' is in a1.__dict__ >> to prevent a lazyload. >> >> from sqlalchemy import * >> from sqlalchemy.orm import * >> from sqlalchemy.ext.declarative import declarative_base >> >> Base = declarative_base() >> >> class A(Base): >> __tablename__ = 'a' >> >> id = Column(Integer, primary_key=True) >> bs = relationship("B", secondary=Table('atob', Base.metadata, >> Column('aid', ForeignKey('a.id')), >> Column('bid', ForeignKey('b.id')) >> ), >> uselist=False) >> >> class B(Base): >> __tablename__ = 'b' >> >> id = Column(Integer, primary_key=True) >> >> e = create_engine("sqlite://", echo=True) >> Base.metadata.create_all(e) >> >> sess = Session(e) >> sess.add(A()) >> sess.commit() >> sess.close() >> >> a1 = sess.query(A).options(joinedload("bs")).first() >> assert 'bs' in a1.__dict__ >> assert a1.__dict__['bs'] is None >> assert a1.bs is None >> >> >> >> -- >> You received this message because you are subscribed to the Google Groups >> "sqlalchemy" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to sqlalchemy+unsubscr...@googlegroups.com. >> To post to this group, send email to sqlalchemy@googlegroups.com. >> Visit this group at http://groups.google.com/group/sqlalchemy. >> For more options, visit https://groups.google.com/d/optout. >> >> >> -- >> You received this message because you are subscribed to the Google Groups >> "sqlalchemy" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to sqlalchemy+unsubscr...@googlegroups.com. >> To post to this group, send email to sqlalchemy@googlegroups.com. >> Visit this group at http://groups.google.com/group/sqlalchemy. >> For more options, visit https://groups.google.com/d/optout. > > > -- > You received this message because you are subscribed to the Google Groups > "sqlalchemy" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to sqlalchemy+unsubscr...@googlegroups.com. > To post to this group, send email to sqlalchemy@googlegroups.com. > Visit this group at http://groups.google.com/group/sqlalchemy. > For more options, visit https://groups.google.com/d/optout. > > > -- > You received this message because you are subscribed to the Google Groups > "sqlalchemy" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to sqlalchemy+unsubscr...@googlegroups.com. > To post to this group, send email to sqlalchemy@googlegroups.com. > Visit this group at http://groups.google.com/group/sqlalchemy. > For more options, visit https://groups.google.com/d/optout. -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+unsubscr...@googlegroups.com. To post to this group, send email to sqlalchemy@googlegroups.com. Visit this group at http://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/d/optout.