Alex Rivera | Logout

How to write Asynchronous LINQ query?

Asked 2008-10-31T01:26:01.163
67

After I read a bunch of LINQ related stuff, I suddenly realized that no articles introduce how to write asynchronous LINQ query.

Suppose we use LINQ to SQL, below statement is clear. However, if the SQL database responds slowly, then the thread using this block of code would be hindered.

var result = from item in Products where item.Price > 3 select item.Name;
foreach (var name in result)
{
    Console.WriteLine(name);
}

Seems that current LINQ query spec doesn't provide support to this.

Is there any way to do asynchronous programming LINQ? It works like there is a callback notification when results are ready to use without any blocking delay on I/O.

Edit
Report

1 Answer

4

I started a simple github project named Asynq to do asynchronous LINQ-to-SQL query execution. The idea is quite simple albeit "brittle" at this stage (as of 8/16/2011):

  1. Let LINQ-to-SQL do the "heavy" work of translating your IQueryable into a DbCommand via the DataContext.GetCommand().
  2. For SQL 200[058], cast up from the abstract DbCommand instance you got from GetCommand() to get a SqlCommand. If you're using SQL CE you're out of luck since SqlCeCommand does not expose the async pattern for BeginExecuteReader and EndExecuteReader.
  3. Use BeginExecuteReader and EndExecuteReader off the SqlCommand using the standard .NET framework asynchronous I/O pattern to get yourself a DbDataReader in the completion callback delegate that you pass to the BeginExecuteReader method.
  4. Now we have a DbDataReader which we have no idea what columns it contains nor how to map those values back up to the IQueryable's ElementType (most likely to be an anonymous type in the case of joins). Sure, at this point you could hand-write your own column mapper that materializes its results back into your anonymous type or whatever. You'd have to write a new one per each query result type, depending on how LINQ-to-SQL treats your IQueryable and what SQL code it generates. This is a pretty nasty option and I don't recommend it since it's not maintainable nor would it be always correct. LINQ-to-SQL can change your query form depending on the parameter values you pass in, for example query.Take(10).Skip(0) produces different SQL than query.Take(10).Skip(10), and perhaps a different resultset schema. Your best bet is to handle this materialization problem p
answered 2011-08-16T21:15:07.947

Your Answer