Future<TNHibernateQuery>
A while ago I added query batching support to NHibernate, so you can execute multiply queries to the database in a single roundtrip. That was well and good, except that you need to know, in advance, what you want to batch. This is often the case, but not nearly enough. Fairly often, I want disparate actions that would be batched together. It just occurred to me that this is entirely possible to do.
In my Rhino Igloo project, I have a lot of places where I have code very similar to this (except it can go for quite a while):
Users.DataSource = Controller.GetUsers(); Issues.DataSource = Controller.GetIssues(); Products.DataSource = Controller.GetProducts(); DataBind();
I solved the problem of batching those by figuring out in advance what I need and then doing a single batch query for all of them, then handing out the result through each of those methods.
This is complicated and sometimes fragile.
What would happen if I could ignore that and instead built API that looked like this?
public FutureOf<User> GetUsers(); public FutureOf<Issue> GetIssues(); public FutureOf<Product> GetProducts();
Where FutureOf<T> would be defined as:
public class FutureOf<T> : IEnumerable<T> { //... }
Now, what is special here, I hear you way. Well, when you start enumerating over a future, it gather all the future queries that has been created so far, executing them in a single batch against the database, and return the results.
Where before I needed to take special care to get this result, now it is just a naturally occurring phenomenon :-)
Neat, if I say so myself.
Comments
Neat idea.
Quite neat. Its probably the definition of the word "neat". No really, I like the idea.
Nice! Are you adding this to Rhino.Common?
As we speak :-)
This is very similar to an idea I had. I look at this as being very similar to the delayed execution model of Linq. I think you could combine this with the ability to specify things like maximum results to pull and how many rows to skip at a delayed point. Typically we only care about paging at the UI level anyway, why force our method signatures do deal with it when the result of the method could be a container like you are using?
I think the batching combined with paging would be awesome. I would love to throw in the ordering functionality as well, but I'm not yet sure how to do that and keep this separate from query behavior.
John,
It is fairly easy to let the client code handle the paging, and it is an interesting idea in many respects. You are correct that UI is usually the only thing that cares about it.
Sorting is more complex, and I don't think you want the UI dictating that, it would mean it has a lot more information about the code than you want it to.
The closest thing I've been able to think of for sorting in the UI layer would be using something like DynamicProxy2 to build a proxy object on top of the resulting type of the query.
Basically the syntax would look something like the following SortBy(SortParameter<Person>().FirstName, SortOrder.Ascending) or something like that.
Now combine this with a generic delayedQuery and you no longer need to provide the type type to your SortParameter method, but instead it could already be typed on the result.
I'm not 100% sold on this implementation yet, but I think it may be moving in a good direction.
Another option is to use expression trees, but just for the sorting. I know what a nightmare evaluating expressions are though, so I'm not sure if that is worth it.
If you make it simple enough to add sorting information to your future query, why not let the UI handle it?
That is not so simple.
A query may involve many entities, which may have several FirstName, etc.
Orderring may also be first level business concern, for that matter
Comment preview