Maybe you're still looking into that, but I still don't understand why this:
merged.orderdetails[0].saleprice causes a new issue to the database. (Also, wondering if some databases allow a primary key to be null...) Thanks again. On Feb 9, 2:50 pm, Kent <k...@retailarchitects.com> wrote: > Ah ha. Thanks for tracking that down, makes sense. > > On Feb 9, 2:25 pm, "Michael Bayer" <mike...@zzzcomputing.com> wrote: > > > Kent wrote: > > > I am on version 0.5.8. > > > part of your issue is this: > > > line1.lineid = '15' > > > should be this: > > > line1.lineid = 15 > > > This because the value comes back from the DB as a numeric, not a string, > > producing the wrong identity key ( (<class '__main__.OrderDetail'>, > > ('0206001A134', '15')) vs (<class '__main__.OrderDetail'>, > > (u'0206001A134', 15)) ). > > > The merge then issues the eager load for the lead order + 1 detail, and a > > second select for the additional detail. > > > > As far as how upset it is making me: well, I certainly have no right > > > to demand this very nice, free software be enhanced or changed: I'm > > > just grateful for it. > > > > We will be supporting clients on webservers that are removed by a long > > > distance from the database server, so I would like to limit the round > > > trips as much as is feasible... > > > > I've taken out most everything and left the logic in a simple case to > > > create the behavior. Here is the script that will demonstrate: > > > > ============================================================================= > > > > from sqlalchemy import * > > > from sqlalchemy.orm import * > > > > engine = create_engine('postgres://dbuser:dbu...@localhost:5444/ > > > dbuser',echo=True) > > > metadata = MetaData() > > > Session = sessionmaker(bind=engine) > > > session = Session() > > > > order_table = Table("orders", metadata, > > > Column("orderid", Unicode, primary_key=True) > > > ) > > > > orderdetail_table = Table("orderdetails",metadata, > > > Column("orderid", Unicode, ForeignKey('orders.orderid'), > > > primary_key=True), > > > Column("lineid", Integer, primary_key=True), > > > Column("saleprice", Numeric, nullable=False) > > > ) > > > > class Order(object): > > > pass > > > > class OrderDetail(object): > > > pass > > > > order_mapper = mapper(Order, order_table, > > > properties=dict(orderdetails=relation(OrderDetail, > > > cascade='all,delete-orphan', > > > single_parent=True, > > > lazy=False, > > > backref=backref('parentorder', > > > cascade='refresh-expire,expunge')))) > > > > orderdetail_mapper = mapper(OrderDetail, orderdetail_table) > > > > metadata.create_all(engine) > > > > o=Order() > > > o.orderid = '0206001A134' #this order exists in the database - You'll > > > need to set add it to the DB > > > > line1=OrderDetail() #line exists in database - You'll need to > > > set add it to the DB > > > line1.orderid = '0206001A134' > > > line1.lineid = '15' > > > > line2=OrderDetail() #new line does not exist in database > > > line2.orderid = '0206001A134' > > > > o.orderdetails = [line1, line2] > > > > # > > > # > > > # Question a above - the following merge results in 3 SELECT > > > statements, but the first > > > # is an eagerly loaded query joined with orderdetails. So, unless the > > > JOIN returned fewer rows > > > # (for example, an inner join instead of outer was used), all the > > > orderdetails should > > > # already be in existence as persistent objects: > > > merged=session.merge(o) > > > > merged in session.new #this order exists in the database > > > > merged.orderdetails[0] > > > merged.orderdetails[0] in session.new # already in database (in new = > > > False) > > > > merged.orderdetails[1] > > > merged.orderdetails[1] in session.new # not yet in database (in new = > > > True) > > > > # > > > # Question b: > > > # Why does this issue another select? The object should have been > > > eagerly loaded, > > > # but even if not that, it was later reSELECTED during the merge() > > > merged.orderdetails[0].saleprice > > > > # > > > # Question c: > > > # Are there databases that allow part of a primary key to be undefined > > > (None)? > > > # That is a foreign concept to me, so I expected this object would > > > realize it > > > # needn't query the database. > > > merged.orderdetails[1].saleprice > > > > ============================================================================= > > > > Thanks in advance, > > > > Kent > > > > On Feb 8, 9:57 pm, Michael Bayer <mike...@zzzcomputing.com> wrote: > > >> On Feb 8, 2010, at 4:12 PM, Kent wrote: > > > >> > Ok, here are my questions: > > > >> > a) The merge eagerloads the order, along with its lines, but then, > > >> > directly afterward, issues two additional SELECT statements for the > > >> > two lines, even though these were already eagerly-loaded. That > > >> > surprised me. Why is that occurring? > > > >> I dont know. I would need more than code fragments to reproduce your > > >> behavior. (nor do I know what version you're on). It doesn't > > >> reproduce with a simple test. > > > >> > b) When I ask for the property .saleprice on the order line, another > > >> > SELECT statement is issued. Why does that occur when it was eagerly > > >> > loaded already? > > > >> Same. If the value is in __dict__ it would not issue another load. > > > >> > c) In the case of line2, can SQLAlchemy be made to realize that part > > >> > of the primary key is not set and therefore there is no reason to > > >> > attempt a fetch from the database? It already detected this was a new > > >> > record during the merge. > > > >> the "fetch for None", meaning issuing a fetch when the primary key was > > >> completely None, was resolved in a recent 0.5 version, probably 0.5.8. > > >> However, a partial primary key is considered to be valid. There is a > > >> flag on the mapper() called allow_null_pks=True which in 0.5 is set to > > >> False by default - it means that partial primary key is not valid. > > >> That flag is not in fact checked by merge() in this case, which is > > >> because the flag was already being removed in 0.6 by the time this fix > > >> went into place. The flag only led to confusion over and over again > > >> when users mapped to outerjoins, and didn't receive rows. Whereas > > >> nobody ever complained about merge issuing a load for None as a key - > > >> the issue was fixed because I noticed it myself. So you're the first > > >> person to ever complain about it, which is unfortunate since it may have > > >> led to a different path for the allow_null_pks flag. I dont like the > > >> flag very much since its obscure and nobody really ever used it unless I > > >> told them to directly. The only other way would be for the mapper to > > >> "guess" if nulls are allowed in the primary key based on the type of > > >> table/join structure its mapped to. So it depends on how upset this > > >> behavior is making you if I really need to find some way for it to > > >> differentiate between None-capable primary keys or not. > > > >> > Thanks in advance. > > > >> > Kent > > > >> > -- > > >> > You received this message because you are subscribed to the Google > > >> Groups "sqlalchemy" group. > > >> > To post to this group, send email to sqlalch...@googlegroups.com. > > >> > To unsubscribe from this group, send email to > > >> sqlalchemy+unsubscr...@googlegroups.com. > > >> > For more options, visit this group > > >> athttp://groups.google.com/group/sqlalchemy?hl=en. > > > > -- > > > You received this message because you are subscribed to the Google Groups > > > "sqlalchemy" group. > > > To post to this group, send email to sqlalch...@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. > > -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To post to this group, send email to sqlalch...@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.