Future Queries

Future Queries

Check out this video about Future Queries for some more information!

With PLINQO, the future is now! Build up a list of queries for the data that you need and the first time any of the results are accessed, PLINQO will retrieve all the data in one round trip to the database server. Reducing the number of trips to the database is a great optimization that makes for smoother, faster running applications. Using this feature is as simple as appending .Future() to the end of your queries. To use the Future Queries please make sure that you are importing the CodeSmith.Data.Linq Namespace. Here is a quick sample:

// build up multiple queries
var q1 = db.User
    .ByEmailAddress("one@test.com")
    .Future();
    
var q2 = db.Task
    .Where(t => t.Summary == "Test")
    .Future();
    
// this triggers the loading of all the future queries
var users = q1.ToList();

 

No data is retrieved until q1.ToList(); is executed. At that time, PLINQO knows to execute all the future queries automatically. The data is both batched and not retrieved until it is needed.

Not only can you queue up execution of queries for the future, the results can be cached as well. Again, PLINQO makes things easy. Here's a quick look at FutureCache.

// cache these results for 120 seconds
var q1 = db.User
    .ByEmailAddress("one@test.com")
    .FutureCache(120);

var q2 = db.Task
    .Where(t => t.Summary == "Test")
    .FutureCache(120);

// this triggers the loading of all the future queries
var users = q1.ToList();

 

Queuing up for the future has never been easier!

The Details

Future queries are created with the extension methods Future(), FutureFirstOrDefault(), or FutureCount().

var db = new TrackerDataContext();

// build up queries
var q1 = db.User
    .ByEmailAddress("one@test.com")
    .Future();
    
var q2 = db.Task
    .Where(t => t.Summary == "Test")
    .Future();
    
// this triggers the loading of all the future queries
var users = q1.ToList();

 

In the example above, there are 2 queries built up, as soon as one of the queries is enumerated, it triggers the batch load of both queries.

var db = new TrackerDataContext();

// base query
var q = db.Task.ByPriority(Priority.Normal);
// get total count
var q1 = q.FutureCount();
// get page
var q2 = q.Skip(pageIndex).Take(pageSize).Future();

// triggers sql execute as a batch
int total = q1.Value;
var tasks = q2.ToList();

 

In this example, we have a common senerio where you want to page a list of tasks. In order for the GUI to setup the paging control, you need a total count. With Future, we can batch together the queries to get all the data in one database call.

Future Query Cache

Future queries can also be cached using the same syntax of FromCache extension method. Each query is cached separately to provide more flexibility.

var db = new TrackerDataContext();

// cache for 120 seconds
CacheSettings cache = new CacheSettings(120);

// build up queries
var q1 = db.User
    .ByEmailAddress("one@test.com")
    .FutureCache(cache);
    
var q2 = db.Task
    .Where(t => t.Summary == "Test")
    .FutureCache(cache);

// this triggers the loading of all the future queries
var users = q1.ToList();

 

How It Works

Future queries work by creating the appropriate IFutureQuery object that keeps the IQuerable. The IFutureQuery object is then stored in IFutureContext.FutureQueries list on the DataContext that created the query. The DataContext must implement IFutureContext. Then, when one of the IFutureQuery objects is enumerated, it calls back to IFutureContext.ExecuteFutureQueries() via the LoadAction delegate. ExecuteFutureQueries builds a batch query from all the stored IFutureQuery objects. Finally, all the IFutureQuery objects are updated with the results from the query.

Limitations

Does not support anonymous types.

Next: LINQ to SQL Profiler