On Jun 18, 2009, at 2:19 PM, millerdev wrote:
> This would be done by the loader strategy (probably a variant of
> LazyLoader), which would issue a single query. The result of that
> query would be used to populate the attributes collection of each item
> on the order.
>
>>
hey Daniel -
Good to have you back on the list.
So this is some variant of, "i have a bunch of objects and I'd like to
issue a single SQL statement representing a set of collections across
all of them". SQLA doesn't have a built in "loader" function like
this, although its been discussed. IMO it's just too much to be going
on automatically with too little understanding required up front,
meaning end users might flip on "super-magic-loading" and then wonder
why some massive query is being triggered by a single attribute load -
if they had already discarded half their objects that would be the
recipients then the query would in fact be quite wasteful. The
controversial part is that you ask for a single attribute on a single
object, but then data is loaded into objects that are "elsewhere" as a
result.
I think Hibernate might have this kind of loading available, I've seen
it in their docs but I doubt its used very much. If it were a highly
requested feature that would see a lot of use, that would help its
case...otherwise it's a complicated feature that's hard to implement,
maintain and support to the degree that a core SQLA feature requires,
mostly in terms of constructing the right SQL for a huge variety of
cases, writing/maintaining all the unit tests for those cases, and
supporting on the mailing list and IRC those users who think they want
to use this feature but don't really understand it (or are hitting
bugs with it).
OTOH, rolling recipes for things like this yourself has no such burden
of working perfectly in all cases at all times for everyone
everywhere, it only needs to work for your immediate needs. I think
the infrastructure exists to construct this feature seamlessly without
the need to hack into LoaderStrategy (though that would be where a
core version of this feature would be created).
You'd start using plain session.query() to get the rows you want, hash
together the collections as desired, and then apply them to the
already loaded objects using the attributes.set_committed_value()
function which is used for this purpose (pseudocode follows)....(also
use trunk rev 6066 since I had to fix set_committed_value()):
from sqlalchemy.orm import attributes
loaded_collections = collections.defaultdict(list)
for parent_pk, obj in session.query(Parent.id, DesiredClass).<figure
out the correct criteria>:
collection = loaded_collections[parent_pk]
collection.append(obj)
for parent_pk, collection in loaded_collections.iteritems():
object = lookup_the_parent_object(parent_pk) # probably
via session.identity_map
attributes.set_committed_value(object, "collectionname",
collection)
note that set_committed_value() blows away any pending changes on the
collection. If that's an issue, you can perform a conditional which
checks for an already existing collection in object.__dict__, or use
attributes.get_history(), etc.
Since you're loading for every object in the result, it seems
reasonable that you'd just issue the above query immediately following
the primary result (when we've considered this feature, that's how we
considered it). But if you truly wanted to trigger the above by a
"lazy" attribute, you can roll the above into a callable, and apply to
any attribute via:
def load_data():
< the above loading logic>
return attributes.ATTR_WAS_SET
state = attrbutes.instance_state(some_object)
state.set_callable("collectionname", load_data)
which means, when you hit some_object.collectionname, load_data is
called, and the return value of ATTR_WAS_SET indicates the callable
populated what it needed, no need for attributes to use the return
value as the collection.
So you could build a subclass of Query which applied all of the above
using a function like ".special_deferred_load(collectionname)", which
would then install the "loader callable" to each element in the result
when that option is selected. The hard part is what I've left out,
i.e. constructing the query to load the child items and finding all
the parent objects that are involved in the load.
--~--~---------~--~----~------------~-------~--~----~
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
-~----------~----~----~----~------~----~------~--~---