Raj Rao
Raj Rao

Reputation: 9138

Var vs IEnumerable when it comes to Entity Framework

If I were to use IEnumerable instead of var in the code example below, will the SQL be generated only during the execution of the foreach statement? Or will it execute as an when the Linq statements are evaluated?

var query = db.Customers.Where (c => c.Age > 18);
query = query.Where (c => c.State == "CO");
var result = query.Select (c => c.Name);

foreach (string name in result)   // Only now is the query executed!
   Console.WriteLine (name);

Another example:

IEnumerable<Order> query = db.Orders.Where(o => o.Amount > 1000);
int orderCount = query.Count();

Would it be better to use var (or IQueryable) as it would be executed a select count(*)... when .Count() is executed or would it be exactly same with the IEnumerable code shown above?

Upvotes: 2

Views: 2715

Answers (3)

Jim Wooley
Jim Wooley

Reputation: 10398

In general, the SQL is generated when GetEnumerator is called on the IQueryable.

In your example, there is a subtle difference that you may want to consider. Let's take your original example:

var query = db.Customers.Where (c => c.Age > 18); 
query = query.Where (c => c.State == "CO"); 
var result = query.Select (c => c.Name); 

In this case if you change your first query to IEnumerable query = ..., then the second line would use the IEnumerable version of the Where extension (LINQ to Objects) rather than the IQueryable one (LINQ to SQL/EF). As a result, when we start iterating, the first where clause is passed to the database, but the second where clause is performed on the client side (because it has already been converted to an IEnumerable).

Another subtle item you want to be aware of is the following type of code:

var query = db.OrderBy(c => c.State);
query = query.Customers.Where(c => c.Age > 18); // Fails: Widening

In this case, since your original query returns IOrderedQueryable rather than IQueryable. If you try to then assign query to the result of the .Where operation, you're trying to widen the scope of the return type and the compiler will refuse to perform that widening. As a result, you have to explicitly specify the baseline type rather than using var:

IQueryable<Customer> query = db.OrderBy(c => c.State);  // Is narrowing rather than widening.
query = query.Customers.Where(c => c.Age > 18); 

Upvotes: 2

devuxer
devuxer

Reputation: 42374

It would make no difference. var is just syntactic sugar. If you hover over var, you will see what type C# thinks your query is.

From http://msdn.microsoft.com/en-us/library/bb383973.aspx

Beginning in Visual C# 3.0, variables that are declared at method scope can have an implicit type var. An implicitly typed local variable is strongly typed just as if you had declared the type yourself, but the compiler determines the type. The following two declarations of i are functionally equivalent:

var i = 10; // implicitly typed
int i = 10; //explicitly typed

If you want to perform actions on your query that SQL wouldn't know what to do with, such as a method defined in your class, then you could use AsEnumerable().

For example:

var query = db.Customers
    .Where(c => c.Age > 18)
    .AsEnumerable()
    .Select(c => GetCustomerViewModel());

//put definition of GetCustomerViewModel() somewhere in the same class

Update

As Omar mentioned, if you want your query to be executed immediately (rather than deferred), use ToList(). This will immediately enumerate the IQueryable/IEnumerable and fill the list with the actual data from the database.

Upvotes: 4

Omar
Omar

Reputation: 40182

Linq queries return IQueryable<> or IEnumerable<>, the execution of both is deferred.

As DanM stated, whether or not you use var or IEnumerable<> it all depends on the return value of the method you're calling: if it's an IEnumerable<> or IQuerable<> it'll be deferred, if you use .ToList(), it'll be executed right away.

When to use var comes down to personal choice/style. I generally use var when the return value is understood from the line of code and variable name or if I'm instantiating a generic with a long declartion, e.g. Dictionary<string, Func<Order, object>>.

From your code, it's clear that a collection of Customers/Orders is returned, so I would use the var keyword. Again, this is a matter of personal preference.

Upvotes: 2

Related Questions