On Oct 20, 2010, at 1:34 PM, Jasper K wrote: > Hi, > > We have a use case where we would like to have "incremental updates" > to existing session objects (ie. populate_existing()-type behaviour > where existing object's lazy-loaded attributes are not reset by > subsequent populate_existing queries).
If I were to implement that, I'd issue Session.expire(obj, ['attrname']) on those attributes which I'd like to be "populated", and then just query normally, not using populate_existing(), which was always a "workaround" feature introduced before we had comprehensive expiration support. > > We have come up with a solution by implementing a subclassed > LazyLoader strategy that returns a No-op function in the > "create_row_processor" (basically skipping line 474 in > sqlalchemy.orm.strategies in version 0.5.8). > Is this a safe place to > put this functionality? Note that this session is never used for > flushing, it is used as a read-only caching session. > > > from sqlalchemy.orm.strategies import LazyLoader > class IncrementalLazyLoader(LazyLoader): > > def create_row_processor(self, *args, **kwargs): > if self.is_class_level: > def new_execute(state, dict_, row, **flags): > pass > return (new_execute, None) > else: > return super(IncrementalLazyLoader, > self).create_row_processor(*args, **kwargs) It's definitely not safe to write a LoaderStrategy right now. The current interface of "return a two tuple" is something that ends up changing all the time, and its actually a 3-tuple in the current tip for 0.6.5. I'd like to come up with some way to make the LoaderStrategy interface have a more resilient API but it also operates at the most performance-critical positiion in the whole ORM, which is why its API is not easily subclassable (it used to be just a simple "populate_instance(self, obj)" type of thing). I originally conceived of LS being something very public and subclassable, but I've never seen anyone actually try - both because there's not too many reasons for it and also because its rare to see someone brave enough to wade in there (so I commend you for that). So it is somewhat ironic that just as I decided "well it looks like nobody uses this on the outside" and committed a non-compatible change someone came along doing it :). As far as a solution here, assuming you don't like the expiration idea, I'm not seeing something that works very well for 0.6. The most obvious is a publically-subclassable LoaderStrategy that presents a constant interface which wouldn't change. Except, in 0.7, we are deprecating *all* of the "subclass X to extend the ORM" classes - they aren't going anywhere but the new way to go will be to register listener functions with known events. There is as yet no event for "populate attribute", though we could certainly add one (though again, I'd need to find a way to sneak it in there without adding latency in the vast majority of cases that don't use this hook). But back to 0.6, something that would work across current 0.6's would be to get the tuple from the superclass, and return a tuple of (None, None, [None]) based on the size you get back - hacky for sure. I don't foresee the "create_row_processor" paradigm changing again for 0.6, though I can't be 100% on that. -- 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.