The difference between IQueryable and IEnumerable
IEnumerable and IQueryable are interfaces that allows you to manipulate and query collections of data. IEnumerable is inherited by IQueryable, that means IQueryable add features to IEnumerable interface.
IEnumerable vs IQueryable
IEnumerable | IQueryable |
System.Collections namespace | System.Linq namespace |
LINQ to Object and LINQ to XML | LINQ to SQL |
NO lazy loading | lazy loading |
in-memory queries | out-memory (serverside) queries |
doesn’t support custom query | supports custom query |
Reference code from microsoft reference source
The following code shows the implementation of the IQueryable.Take() method.
The method creates a query on source provider to return top N elements.
public static IQueryable Take(this IQueryable source, int count) | |
{ | |
if (source == null) | |
throw Error.ArgumentNull("source"); | |
return source.Provider.CreateQuery( | |
Expression.Call( | |
null, | |
((MethodInfo)MethodBase.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)), | |
new Expression[] { source.Expression, Expression.Constant(count) } | |
)); | |
} |
The following code shows the implementation of the IEnumerable.Take() method.
The method simply uses a foreach to return the top N elements.
[TestMethod] | |
public void IEnumerableBehavior() | |
{ | |
IEnumerable<Product> products = dc.Product | |
//This expression produces an SQL query | |
.Where(p => p.Name.Contains("LL")); | |
//IEnumerable: the following statement is an in-memory query | |
products = products.Take<Product>(100); | |
} |
Example
The following example shows the difference between IQueryable and IEnumerable:
[TestMethod] | |
public void IEnumerableBehavior() | |
{ | |
IEnumerable<Product> products = dc.Product | |
//This expression produces an SQL query | |
.Where(p => p.Name.Contains("LL")); | |
//IEnumerable: the following statement is an in-memory query | |
products = products.Take<Product>(100); | |
} |
The first statement uses the IQueryable interface, in fact it performs a query on data source and assigns the result to an IEnumerable variable.
The next operation is executed in-memory because they queriy use IEnumerable interface.
We can use SQL profiler to monitor the executed query:
SELECT | |
[Extent1].[ProductID] AS [ProductID], | |
[Extent1].[Name] AS [Name], | |
[Extent1].[ProductNumber] AS [ProductNumber], | |
[Extent1].[MakeFlag] AS [MakeFlag], | |
[Extent1].[FinishedGoodsFlag] AS [FinishedGoodsFlag], | |
[Extent1].[Color] AS [Color], | |
[Extent1].[SafetyStockLevel] AS [SafetyStockLevel], | |
[Extent1].[ReorderPoint] AS [ReorderPoint], | |
[Extent1].[StandardCost] AS [StandardCost], | |
[Extent1].[ListPrice] AS [ListPrice], | |
[Extent1].[SIZE] AS [SIZE], | |
[Extent1].[SizeUnitMeasureCode] AS [SizeUnitMeasureCode], | |
[Extent1].[WeightUnitMeasureCode] AS [WeightUnitMeasureCode], | |
[Extent1].[Weight] AS [Weight], | |
[Extent1].[DaysToManufacture] AS [DaysToManufacture], | |
[Extent1].[ProductLine] AS [ProductLine], | |
[Extent1].[Class] AS [Class], | |
[Extent1].[STYLE] AS [STYLE], | |
[Extent1].[ProductSubcategoryID] AS [ProductSubcategoryID], | |
[Extent1].[ProductModelID] AS [ProductModelID], | |
[Extent1].[SellStartDate] AS [SellStartDate], | |
[Extent1].[SellEndDate] AS [SellEndDate], | |
[Extent1].[DiscontinuedDate] AS [DiscontinuedDate], | |
[Extent1].[rowguid] AS [rowguid], | |
[Extent1].[ModifiedDate] AS [ModifiedDate] | |
FROM [Production].[Product] AS [Extent1] | |
WHERE [Extent1].[Name] LIKE N'%LL%' |
We can perform the same operations using IQueryable interface, all queries will be performed on data source:
[TestMethod] | |
public void IQueryableBehavior() | |
{ | |
IQueryable<Product> list = dc.Product | |
//IQueryable: this expression produces an SQL query | |
.Where(p => p.Name.Contains("LL")); | |
//IQueryable: this expression produces an SQL query | |
list = list.Take<Product>(100); | |
} |
The SQL query will filter the result, and will use the SQL statement “TOP(100)”:
SELECT TOP (100) | |
[Extent1].[ProductID] AS [ProductID], | |
[Extent1].[Name] AS [Name], | |
[Extent1].[ProductNumber] AS [ProductNumber], | |
[Extent1].[MakeFlag] AS [MakeFlag], | |
[Extent1].[FinishedGoodsFlag] AS [FinishedGoodsFlag], | |
[Extent1].[Color] AS [Color], | |
[Extent1].[SafetyStockLevel] AS [SafetyStockLevel], | |
[Extent1].[ReorderPoint] AS [ReorderPoint], | |
[Extent1].[StandardCost] AS [StandardCost], | |
[Extent1].[ListPrice] AS [ListPrice], | |
[Extent1].[SIZE] AS [SIZE], | |
[Extent1].[SizeUnitMeasureCode] AS [SizeUnitMeasureCode], | |
[Extent1].[WeightUnitMeasureCode] AS [WeightUnitMeasureCode], | |
[Extent1].[Weight] AS [Weight], | |
[Extent1].[DaysToManufacture] AS [DaysToManufacture], | |
[Extent1].[ProductLine] AS [ProductLine], | |
[Extent1].[Class] AS [Class], | |
[Extent1].[STYLE] AS [STYLE], | |
[Extent1].[ProductSubcategoryID] AS [ProductSubcategoryID], | |
[Extent1].[ProductModelID] AS [ProductModelID], | |
[Extent1].[SellStartDate] AS [SellStartDate], | |
[Extent1].[SellEndDate] AS [SellEndDate], | |
[Extent1].[DiscontinuedDate] AS [DiscontinuedDate], | |
[Extent1].[rowguid] AS [rowguid], | |
[Extent1].[ModifiedDate] AS [ModifiedDate] | |
FROM [Production].[Product] AS [Extent1] | |
WHERE [Extent1].[Name] LIKE N'%LL%' |