I noticed few issues in gunny229's answer. I've mentioned those issues in comment area of his post. Later on, I thought to write a more detailed post to connect some missing dots.
Disclaimer: I don't intend to cater OP's question in entirety but I 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 get top 2 records from Employee table in database. I created a new C# console application in Visual Studio (VS). Then, I added an ADO.NET Entity Data Model XML (EDMX) item pointing to Employee table in the database. Now I can start writing LINQ queries.
Case I: 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);
}
}
Before running this program, I had started a session of SQL Query profiler on the SQL Server instance. 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]
We can see 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 network. No more in-memory filtering is required on the client side.
Case II: 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 to note is that IEnumerable brought all the 5 records present in Salary table and then performed an in-memory filteration on the client side to get top 2 records. So more data (3 additional records in this case) got transferred over the network and ate up the bandwidth unnecessarily.