Adaptive Fetching Strategies in ORMs
Aaron has a post about some wild ideas about OR/M fetching, specifically, auto-learning fetching strategies. The idea has merit, and the required technicalities are already inside NHibernate, I can imagine a proxy that talks to to fetching strategy to inform it about accessed properties, which would give it the information needed for the next time the same query is made.
But, how do you correlate queries?
I have "Repository<Salary>.FindAll(Where.Salary.Employee == CurrentEmployee);" in several places, in the "list employee salaries page" and in the "calculate tax" service. Each requires a different fetching strategy. Worse, I have this hiding in a method call GetEmployeeSalaries(Employee), so now we can't even use the callsite information to do our smarts.
We can try to do something with stack traces, but I am not sure that this is something that you would really want to do, as this has performance implications of its own.
Comments
You would associate the strategy at a much higher level, much the same way Udi does it in his FetchingStrategy example. So instead of your example, you'd have:
Repository<FetchingStrategy>.FindAll<Salary>(Where.Salary.Employee == CurrentEmployee).
FetchingStrategy could be anything we wanted it to be, like your service that is making the query's interface. Heck, you could even tie it into monorail's request somehow so each action had its own strategy, but I don't like that very much, I'd rather be able to reuse my strategies.
I did think of the stack trace idea, but I'd worry about performance on that one... not to mention the fact that its kind of hackish IMO.
Oren,
I left a comment on Aaron's post before reading your post, and I basically said what you are saying... i.e. how do you distingush between strategies. I can see three 3 possibilities:
1) provide a strategy directly (i.e. explicit i.e. akin to Scoping or Expand from Astoria not sure what NHibernate calls this).
2) provide an explicit name to the implicitly created strategy via the API i.e.
"Repository<Salary>.FindAll(Where.Salary.Employee == CurrentEmployee, "Strategy1");"
3) make everything implicit, automate everything using the stacktrace or something. Which is simply a variation on (2) where the name is implicitly derived from the stacktrace.
I think I like the idea of (2) best for what Aaron is talking about. (3) looks like it brings with it performance baggage of it's own (as you pointed out...)
Another nice thing about (2) is that at some later date you could get the tuned strategy "Repository<Salary>.GetStrategy("Strategy1")" and prehaps re-use it in directly somewhere else.
Interesting idea.
Oh, and with regards to it hiding behind a method, you'd need to poke a hole in that method to let the context get through GetEmployeeSalaries(Employee, typeof(strategy)) or GetEmployeeSalaries<strategy>(Employee). There's just no good way around that.
I guess you could also handle it like you would transactions (and along side them):
With.Transaction<Strategy>()
{
}
etc.
OK, let me back pedal a bit, Jacob and I talked about it some more and the transaction level stuff would be a bad idea... several queries could happen within there and it would get rather confusing to store strategies for each and differentiate them. That said, I think ultimately every strategy needs to be named somehow like Alex says. It makes sense, I mean, they are different queries. Either with strings or types or whatever. I'm starting to lean towards strings now actually, but they'd have to be type safe constants... you know how much we hate string literals :)
Also, to be clear, whatever is doing the proxying (NHibernate's EntityPersister or whatever actually does it,) would need to be made aware of the strategy, so a hole would have to be poked all the way down to the actual NHib Query/Criteria api.
I just spiked it, it is very easy to get informed about property level access, but getting notified about collection load is harder.
...Earlier in the week I had a discussion in comments with both Ayende and Aaron here and here about adaptive fetching strategies. Good times...
Anyway... I was just reviewing Mike Taulty's latest post (in a long series about LINQ, XLINQ, DLINQ you name it really) and he has posted an example of how the DLINQ people associate a fetching strategy with the current context. I really like it...
Comment preview