Thursday, July 24, 2008

Reusing runtime compiled LINQ queries

Sometimes I want to execute the same LINQ generated SQL statement multiple times with different parameters, but don't want the overhead of conversion from an expression tree to the actual SQL statement to occur each time. I did some research and found that you can cache the compiled query using the CompiledQuery.Compile method which allows you to store the compiled method into a Func variable.
In the example below I am caching a query to get Employees by City in the Northwind database. The GetByCity method exposes the stored function to the caller and will only compile the query the first time it is executed.
using System;
using System.Data.Linq;
using System.Linq;

namespace NorthwindSandbox
{
public static class Class1
{
public static void Main()
{
var db = new NorthwindDataContext();

DisplayEmployeesByCity( db, "London" );
DisplayEmployeesByCity( db, "Seattle" );
DisplayEmployeesByCity( db, "Walrus" );

Console.ReadKey();
}

private static void DisplayEmployeesByCity (
NorthwindDataContext db, string city )
{
Console.WriteLine(
string.Concat( city, " Employees: " ) );

IQueryable< Employee > employees =
Employee.GetByCity( db, city );

foreach ( Employee e in employees )
{
string name = string.Concat(
e.FirstName, " ", e.LastName );

Console.WriteLine( name );
}

Console.WriteLine();
}
}

partial class Employee
{
private static Func< NorthwindDataContext,
string, IQueryable< Employee > > byCity_;

public static IQueryable< Employee > GetByCity(
NorthwindDataContext dbContext,
string cityName )
{
if ( byCity_ == null )
{
byCity_ = CompiledQuery.Compile(
( NorthwindDataContext db, string city )
=> from employee in db.Employees
where employee.City == city
select employee );
}

return byCity_( dbContext, cityName );
}
}
}

No comments: