I am on version 0.5.8. 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.