Linq-to-Entities Projection Queries:

Here, you will learn how to write LINQ-to-Entities queries and get the result entities. Visit LINQ Tutorials to learn LINQ step by step.

Projection is a process of selecting data in a different shape rather than a specific entity being queried. There are many ways of projection. We will now see some projection styling:

First/FirstOrDefault:

If you want to get a single student object, when there are many students, whose name is "Student1" in the database, then use First or FirstOrDefault, as shown below:

using (var ctx = new SchoolDBEntities())
{    
    var student = (from s in ctx.Students
                where s.StudentName == "Student1"
                select s).FirstOrDefault<Student>();
}
    

The above query will result in the following database query:

SELECT TOP (1) 
[Extent1].[StudentID] AS [StudentID], 
[Extent1].[StudentName] AS [StudentName], 
[Extent1].[StandardId] AS [StandardId]
FROM [dbo].[Student] AS [Extent1]
WHERE 'Student1' = [Extent1].[StudentName]

The difference between First and FirstOrDefault is that First() will throw an exception if there is no result data for the supplied criteria whereas FirstOrDefault() returns default value (null) if there is no result data.

Single/SingleOrDefault:

You can also use Single or SingleOrDefault to get a single student object as shown below:

using (var ctx = new SchoolDBEntities())
{    
    var student = (from s in context.Students
                    where s.StudentID == 1
                    select s).SingleOrDefault<Student>();
}

The above query would execute the following database query:

SELECT TOP (2) 
[Extent1].[StudentID] AS [StudentID], 
[Extent1].[StudentName] AS [StudentName], 
[Extent1].[StandardId] AS [StandardId]
FROM [dbo].[Student] AS [Extent1]
WHERE 1 = [Extent1].[StudentID]
go

Single or SingleOrDefault will throw an exception, if the result contains more than one element. Use Single or SingleOrDefault where you are sure that the result would contain only one element. If the result has multiple elements then there must be some problem.

ToList:

If you want to list all the students whose name is 'Student1' (provided there are many students has same name) then use ToList():

using (var ctx = new SchoolDBEntities())
{    
    var studentList = (from s in ctx.Students
    where s.StudentName == "Student1"
    select s).ToList<Student>();
}
    

The above query would result in the following database query:

SELECT 
[Extent1].[StudentID] AS [StudentID], 
[Extent1].[StudentName] AS [StudentName], 
[Extent1].[StandardId] AS [StandardId]
FROM [dbo].[Student] AS [Extent1]
WHERE 'Student1' = [Extent1].[StudentName]
go

GroupBy:

If you want to group students by standardId, then use groupby:

using (var ctx = new SchoolDBEntities())
{    
    var students = from s in ctx.Students 
                   group s by  s.StandardId into studentsByStandard
                   select studentsByStandard;
}
    

The above query would execute the following database query:

SELECT 
[Project2].[C1] AS [C1], 
[Project2].[StandardId] AS [StandardId], 
[Project2].[C2] AS [C2], 
[Project2].[StudentID] AS [StudentID], 
[Project2].[StudentName] AS [StudentName], 
[Project2].[StandardId1] AS [StandardId1]
FROM ( SELECT 
    [Distinct1].[StandardId] AS [StandardId], 
    1 AS [C1], 
    [Extent2].[StudentID] AS [StudentID], 
    [Extent2].[StudentName] AS [StudentName], 
    [Extent2].[StandardId] AS [StandardId1], 
    CASE WHEN ([Extent2].[StudentID] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C2]
    FROM   (SELECT DISTINCT 
        [Extent1].[StandardId] AS [StandardId]
        FROM [dbo].[Student] AS [Extent1] ) AS [Distinct1]
    LEFT OUTER JOIN [dbo].[Student] AS [Extent2] ON ([Distinct1].[StandardId] = [Extent2].[StandardId]) OR (([Distinct1].[StandardId] IS NULL) AND ([Extent2].[StandardId] IS NULL))
)  AS [Project2]
ORDER BY [Project2].[StandardId] ASC, [Project2].[C2] ASC
go

OrderBy:

If you want to get the list of students sorted by StudentName, then use OrderBy:

using (var ctx = new SchoolDBEntities())
{    
        var student1 = from s in ctx.Students
                    orderby s.StudentName ascending
                    select s;
}
    

The above query would execute the following database query:

SELECT 
[Extent1].[StudentID] AS [StudentID], 
[Extent1].[StudentName] AS [StudentName], 
[Extent1].[StandardId] AS [StandardId]
FROM [dbo].[Student] AS [Extent1]
ORDER BY [Extent1].[StudentName] ASC
go

Anonymous Class result:

If you want to get only StudentName, StandardName and list of Courses for that student in a single object, then write the following projection:

using (var ctx = new SchoolDBEntities())
{    
    var projectionResult = from s in ctx.Students
                        where s.StudentName == "Student1"
                        select new { 
                        s.StudentName, s.Standard.StandardName, s.Courses 
                        };
}
    

The above query would execute the following database query:

SELECT 
[Extent1].[StudentID] AS [StudentID], 
[Extent1].[StudentName] AS [StudentName], 
[Extent2].[City] AS [City]
FROM  [dbo].[Student] AS [Extent1]
LEFT OUTER JOIN [dbo].[StudentAddress] AS [Extent2] ON [Extent1].[StudentID] = [Extent2].[StudentID]
WHERE 1 = [Extent1].[StandardId]
go

The projectionResult in the above query will be the anonymous type, because there is no class/entity which has these properties. So, the compiler will mark it as anonymous.

Nested queries:

You can also execute nested LINQ to entity queries as shown below:

entity relationships in entity framework

The nested query shown above will result in an anonymous list with a StudentName and Course object.

SELECT 
[Extent1].[StudentID] AS [StudentID], 
[Extent1].[StudentName] AS [StudentName], 
[Join1].[CourseId1] AS [CourseId], 
[Join1].[CourseName] AS [CourseName], 
[Join1].[Location] AS [Location], 
[Join1].[TeacherId] AS [TeacherId]
FROM  [dbo].[Student] AS [Extent1]
INNER JOIN  (SELECT [Extent2].[StudentId] AS [StudentId], [Extent3].[CourseId] AS [CourseId1], [Extent3].[CourseName] AS [CourseName], [Extent3].[Location] AS [Location], [Extent3].[TeacherId] AS [TeacherId]
    FROM  [dbo].[StudentCourse] AS [Extent2]
    INNER JOIN [dbo].[Course] AS [Extent3] ON [Extent3].[CourseId] = [Extent2].[CourseId] ) AS [Join1] ON [Extent1].[StudentID] = [Join1].[StudentId]
WHERE 1 = [Extent1].[StandardId]
go

In this way, you can do a projection of the result, in the way that you would like the data to be.