I noticed several issues in @gunny229's answer above which is why I'm writing this post. I've mentioned those issues in comment area of his post as well. To correct that post I would have had to rewrite almost entire post so I thought of creating my own. I don't intend to cater OP's question in entirety but I'm want to point out the difference between IQueryable and IEnumerable when using LINQ to SQL.
I created following structure in DB (DDL script):
CREATE TABLE [dbo].[Employee]([PersonId] [int] NOT NULL PRIMARY KEY,[Salary] [int] NOT NULL)
Here is the record insertion script (DML script):
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(1, 20)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(2, 30)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(3, 40)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(4, 50)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(5, 60)
GO
Now my goal was to simply get top 2 records from Employee
table in database. So, I added an ADO.NET Entity Data Model item into my console application pointing to Employee
table in my database and started writing LINQ queries.
Code for IQueryable route:
using (var efContext = new EfTestEntities())
{
IQueryable<int> employees = from e in efContext.Employees select e.Salary;
employees = employees.Take(2);
foreach (var item in employees)
{
Console.WriteLine(item);
}
}
When I started to run this program, I had also started a session of SQL Query profiler on my SQL Server instance and here is the summary of execution:
- Total number of queries fired: 1
- Query text:
SELECT TOP (2) [c].[Salary] AS [Salary] FROM [dbo].[Employee] AS [c]
It is just that IQueryable
is smart enough to apply the Top (2)
clause on database server side itself so it brings only 2 out of 5 records over the wire. Any further in-memory filtering is not required at all on client computer side.
Code for IEnumerable route:
using (var efContext = new EfTestEntities())
{
IEnumerable<int> employees = from e in efContext.Employees select e.Salary;
employees = employees.Take(2);
foreach (var item in employees)
{
Console.WriteLine(item);
}
}
Summary of execution in this case:
- Total number of queries fired: 1
- Query text captured in SQL profiler:
SELECT [Extent1].[Salary] AS [Salary]
FROM [dbo].[Employee] AS [Extent1]
Now the thing is IEnumerable
brought all the 5 records present in Salary
table and then performed an in-memory filtering on the client computer to get top 2 records. So more data (3 additional records in this case) got transferred over the wire unnecessarily.