How to maintain LINQ deferred execution?

You have to be really careful about passing around IQueryables when you're using a DataContext, because once the context get's disposed you won't be able to execute on that IQueryable anymore. If you're not using a context then you might be ok, but be aware of that Any() and .FirstOrDefault() are not deferred. When you call them they will cause execution to occur.

However, this may not do what you think it does. For instance, in LINQ to SQL if you perform an .Any() on an IQueryable it acts as a IF EXISTS( SQL HERE ) basically You can chain IQueryable's along like this if you want to: var firstQuery = from f in context. Foos where f.

Bar == bar select f; var secondQuery = from f in firstQuery where f. Bar == anotherBar orderby f. SomeDate select f; if (secondQuery.Any()) //immediately executes IF EXISTS( second query in SQL ) { //causes execution on second query //and allows you to enumerate through the results foreach (var foo in secondQuery) { //do something } //or //immediately executes second query in SQL with a TOP 1 //or something like that var foo = secondQuery.FirstOrDefault(); }.

You have to be really careful about passing around IQueryables when you're using a DataContext, because once the context get's disposed you won't be able to execute on that IQueryable anymore. If you're not using a context then you might be ok, but be aware of that. .Any() and .FirstOrDefault() are not deferred.

When you call them they will cause execution to occur. However, this may not do what you think it does. For instance, in LINQ to SQL if you perform an .Any() on an IQueryable it acts as a IF EXISTS( SQL HERE ) basically.

You can chain IQueryable's along like this if you want to: var firstQuery = from f in context. Foos where f. Bar == bar select f; var secondQuery = from f in firstQuery where f.

Bar == anotherBar orderby f. SomeDate select f; if (secondQuery.Any()) //immediately executes IF EXISTS( second query in SQL ) { //causes execution on second query //and allows you to enumerate through the results foreach (var foo in secondQuery) { //do something } //or //immediately executes second query in SQL with a TOP 1 //or something like that var foo = secondQuery.FirstOrDefault(); }.

It sounds like in #1, having a method that essentially constructs a new IQueryable each time is a good thing since this way I won't run into issues with disposal. In #2, I'm confused how LINQ-to-SQL can translate the Any operator, yet I cannot defer. If I were to use an Any operator within a larger query is it immediately executed there as well, or is it part of the larger query execution?

– McKAMEY Aug 20 '09 at 19:16 @McKAMEY I'll edit my answer to try and better illustrate. – Joseph Aug 20 '09 at 19:38 OK I think I'm almost there. If I were to embed an .Any() into a where clause then it wouldn't execute that in a loop, correct?

It would compile to the appropriate SQL expression and send that down. So in effect, it isn't .Any() that prevents deferred execution as it is how it is being used. Basically if the result of a whole query is a scalar then the compiler figures you need the result now rather than continuing with building up an IQueryable.

– McKAMEY Aug 21 '09 at 15:13 1 @McKAMEY correct, as soon as you use .Any() in a context that is not deferrable then it will execute. In the case of .Where() it's looking for an expression, which is deferrable, so you're ok. In the case of var or the foreach loop, those cause execution becuase they are not deferrable.

– Joseph Aug 21 '09 at 15:42 I think that answers my whole question. Thanks! – McKAMEY Aug 21 '09 at 15:53.

A much better option than caching IQueryable objects is to cache Expression trees. All IQueryable objects have a property called Expression (I believe), which represents the current expression tree for that query. At a later point in time, you can recreate the query by calling queryable.Provider.

CreateQuery(expression), or directly on whatever the provider is (in your case a Linq2Sql Data Context). Parameterizing these expression trees is slightly harder however, as they use ConstantExpressions to build in a value. In order to parameterize these queries, you WILL have to rebuild the query every time you want different parameters.

1 I would say that parameterizing (or more importantly encapsulating a single unit of logic) is the real goal here rather than caching. Considering that the C# compiler has already converted it, I don't think that a runtime equivalent would be of much use / performance benefit (as is what caching implies). – McKAMEY Aug 21 '09 at 15:06.

Any() used this way is deferred. Var q = dc.Customers. Where(c => c.Orders.Any()); Any() used this way is not deferred, but is still translated to SQL (the whole customers table is not loaded into memory).

Bool result = dc.Customers.Any(); If you want a deferred Any(), do it this way: public static class QueryableExtensions { public static Func DeferredAny(this IQueryable source) { return () => source.Any(); } } Which is called like this: Func f = dc.Customers.DeferredAny(); bool result = f(); The downside is that this technique won't allow for sub-querying.

When you say deferred, it sounds like you mean I can define a lambda expression (or delegate) but not immediately execute it. I think there is a subtlety to LINQ's concept of "deferred execution" which allows the operation to become part of a larger expression tree, which can be interpreted by the provider however it wants. My question is more trying to get at what are the limitation differences between IQueryable.

Where(Expression>) vs. IQueryable. Any(Expression>) as it seems as though the latter isn't as flexible. – McKAMEY Aug 20 '09 at 21:15 1 That inflexibility comes from the difference in return types.

The type named 'bool' can have no deferred behavior. – David B Aug 20 '09 at 23:41 this suggestion seems thread-unsafe to me (consider the DataContext) – cottsak Oct 15 '09 at 11:46 @cottsak - all extension methods (including the ones for linq) are static, such as msdn.microsoft. Com/en-us/library/bb535040.

Aspx . Static methods are threadsafe as long as there is no static state (such as a static property or field). – David B Oct 15 '09 at 13:55 good response.

Didn't know that. Makes good sense actually. Thanx – cottsak Nov 7 '09 at 19:19.

Create a partial application of your query inside an expression FuncBar,IQueryableBlah,IQueryableFoo queryMaker = (criteria, queryable) => from foo in queryable. Foos where foo. Bar == criteria select foo; and then you can use it by ... IQueryableBlah blah = context.

Blah; Bar someCriteria = new Bar(); IQueryableFoo someFoosQuery = queryMaker(blah, someCriteria); The query could be encapsulated within a class if you want to make it more portable / reusable. Public class FooBarQuery { public Bar Criteria { get; set; } public IQueryableFoo GetQuery( IQueryableBlah queryable ) { return from foo in queryable. Foos where foo.

Bar == Criteria select foo; } }.

Edit: Part 2 is really more about trying to understand what are the limitation differences between IQueryable. Where(Expression>) vs. IQueryable. It seems as though the latter isn't as flexible when creating larger queries where the execution is to be delayed.

The Where() can be appended and then other constructs can be later appended and then finally executed. Since the Any() returns a scalar value it sounds like it will immediately execute before the rest of the query can be built.

I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.

Related Questions