Precompiling LINQ Queries in .NET Framework 4.5

While it is possible to precompile LINQ queries for Entity Framework either to have your queries run faster (either without parameters or with parameters) or to run your queries on a background thread, in .NET Framework 3.5/4, it’s neither pretty nor fun. The code isn’t particularly ugly but it does require some additional effort for you to have your queries precompiled. Unless you want to run your statement on a background thread, you’ll only benefit from precompiling if you execute the same LINQ statement many times (and, even then, if your queries aren’t very complex then you still may not get much benefit).

However, there is some benefit from precompiling and it would be nice to have it, provided you didn’t have to do any extra work. That’s where .NET Framework 4.5 steps in. While it’s always dangerous to talk about what’s supposed to be in an upcoming version of some software, the intent is for the framework to recycle your compiled LINQ queries (a feature called “auto-compiled LINQ queries”). Every time a LINQ statement is issued, the framework will build the statement’s expression tree (the first step in the compilation process) and generate a unique identifier for the statement. The framework will then search a cache to see if that identifier is already present. If the framework doesn’t find the identifier, the framework finishes the compilation process and adds the compiled version of the statement to the cache before executing it; if the framework finds the identifier, it uses the already compiled version of the statement.

Notice what’s happening here: You still have to pay for the statement’s expression tree to be generated but, once you’ve paid that cost, if your statement or one very much like it already exists in the cache then all subsequent compile steps are skipped and your statement is just executed. If you have the identical LINQ statement in several places in your application then there’s no need—from an efficiency point of view—to rewrite your application to have that LINQ statement appear only once. The cache will store only one version of the statement and use it from all the places it appears in your application (of course, you’d want to have a good reason for scattering an identical LINQ expression throughout your code). As an added benefit, statements are only compiled if they are used. The older precompile method meant that you could precompile a LINQ statement that you might never use.

You don’t have access to the compiled queries in the cache (at least, not yet) so you’ll need to continue using CompiledQuery if you want to execute your LINQ statement on a background thread.

Turning Off Auto-Compile

If you don’t want to have your statements precompiled, you can turn the feature off by setting the DefaultQueryPlanCachingSetting on the ObjectContext’s ContextOptions property to false, like this:

oc.ContextOptions.DefaultQueryPlanCachingSetting = false;

I can only see two scenarios when turning off this option would be a good thing. Turning off auto-compile would eliminate whatever cost is involved in generating the identifier and walking the cache but, I’m willing to assume, that will be more than offset by not compiling a LINQ statement more than once. If you have a LINQ statement which is only executed once (and, furthermore, if this is true of all the LINQ statements associated with this instance of the ObjectContext) then setting this option to false would probably be a good choice. In this scenario, there’s also no benefit in using the CompiledQuery class to precompile your queries.

The second scenario involves sticking with the CompiledQuery class. Because there is a cost associated with maintaining and searching the cache, using the CompiledQuery class should give you better performance than the auto-compile option—no need to generate an identifier or maintain the cache (provided, of course, you don’t precompile statements you never use). If you’re obsessed with performance and don’t mind the extra work (or are paid by the hour) you could stick with the CompiledQuery class, even in .NET Framework 4.5. In this scenario, you may need to turn off DefaultQueryPlanCachingSetting to prevent the framework from also maintaining its cache of auto-compiled statements.

One last note: This does mean that if you’re using the CompiledQuery class in your existing code then, when you upgrade to .NET Framework 4.5, you’ll actually be getting better performance than the programmers who count on the framework’s default behaviour.

Peter Vogel

2 Responses to “Precompiling LINQ Queries in .NET Framework 4.5”


  1. 1 Jerry December 8, 2011 at 7:29 pm

    Awesome series of articles! Linq to Entities totally rocks. From creating the EDM to binding to data aware controls in less than 15 minutes. .Net Framework 4.5 is looking really good to me at this point.

    Am I understanding correctly; with framework 4.5 we get the benefit of delegated compiled LINQ Queries (asynchronous if needed) only created when the delegate gets invoked, NOT when the class is created (constructor called). Basically we can instantiate the data class, and only when (and if) a public member is referenced, does the compiling happen?

    • 2 Peter Vogel, Learning Tree December 8, 2011 at 9:00 pm

      Not quite–the auto-compile that you get with .NET 4.5 may or may not be creating a delegate but (right now and to the best of my knowledge) it doesn’t matter because you won’t have access to the delegate. So you won’t be able to run the compiled query asynchronously.

      As to when is the compilation is performed: It appears that the the cache is searched for a compiled version of the query when the LINQ query is executed (again, we’re talking about a future version of the software so, who knows?). As long as you aren’t using the conversion functions (e.g. ToList, ToArray), execution is deferred until you request individual members of the collection returned by the LINQ statement.

      Assuming code like this

      Dim oc As New NorthwindEntities

      Dim res = From c In oc.Orders
      Select Orders

      For Each ord As Order in rec
      ….
      Next

      As I read the description of this feature: It will be at the start of the For Each loop that the cache of compiled statements will be searched and, if no matching entry is found, the query compiled. So, if your public member contains the For Each loop and the constructor contains the rest of the code shown above, my understanding is that you won’t pay for the compilation if the public member isn’t referenced. But I’m willing to be wrong about this…


Comments are currently closed.



Learning Tree International

.NET & Visual Studio Courses

Learning Tree offers over 210 IT training and Management courses, including a full curriculum of .NET training courses.

Free White Papers

Questions on current IT or Management topics? Access our Complete Online Resource Library of over 65 White Papers, Articles and Podcasts

Enter your email address to subscribe to this blog and receive notifications of new posts by e-mail.

Join 29 other followers

Follow Learning Tree on Twitter

Archives

Do you need a customized .NET training solution delivered at your facility?

Last year Learning Tree held nearly 2,500 on-site training events worldwide. To find out more about hosting one at your location, click here for a free consultation.
Live, online training

%d bloggers like this: