LINQ-to-Entities trong Entity Framework

Lớp DbSet có nguồn gốc từ interface IQuerayable. Vì vậy, chúng ta có thể sử dụng LINQ để truy vấn DbSet và những truy vấn này sẽ được chuyển đổi thành truy vấn SQL.

Entity Framework API thực thi truy vấn SQL này vào cơ sở dữ liệu, lấy danh sách kết quả trả về, chuyển đổi nó thành các đối tượng thực thể phù hợp và trả về nó dưới dạng kết quả truy vấn.

Sau đây là một số phương thức mở rộng có thể được sử dụng với các truy vấn LINQ-to-Entities.

Phương thức mở rộng của LINQ
First()
FirstOrDefault()
Single()
SingleOrDefault()
ToList()
Count()
Min()
Max()
Last()
LastOrDefault()
Average()

Phương thức Find()

Ngoài các phương thức mở rộng LINQ, chúng ta có thể sử dụng phương thức Find() của DbSet để tìm kiếm thực thể dựa trên giá trị khóa chính.

Chúng ta sẽ sử dụng SchoolDbEntities ở các chương trước là lớp DbContext và nó có thuộc tính Students là một thuộc tính DbSet.

var ctx = new SchoolDBEntities();
var student = ctx.Students.Find(1);

Trong ví dụ trên, phương thức ctx.Student.Find(1) trả về thông tin của một sinh viên có StudentId là 1 trong cơ sở dữ liệu. Nếu không có bản ghi nào được tìm thấy, thì nó trả về null. Truy vấn trên sẽ thực hiện truy vấn SQL sau.

SELECT 
[Extent1].[StudentID] AS [StudentID], 
[Extent1].[StudentName] AS [StudentName], 
[Extent1].[StandardId] AS [StandardId]
FROM [dbo].[Student] AS [Extent1]
WHERE [Extent1].[StudentId] = @p0',N'@p0 int',@p0=1
go

Phương thức First() / FirstOrDefault()

Nếu bạn muốn lấy một đối tượng sinh viên trong những sinh viên có tên là "Bill" trong cơ sở dữ liệu, thì hãy sử dụng phương thức First hoặc FirstOrDefault, như ví dụ bên dưới:

Cú pháp truy vấn LINQ:

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

Cú pháp phương thức LINQ:

using (var ctx = new SchoolDBEntities())
{    
    var student = ctx.Students
                     .Where(s => s.StudentName == "Bill")
                     .FirstOrDefault<Student>();
}

EF 6 thực hiện truy vấn SQL sau trong cơ sở dữ liệu cho truy vấn LINQ ở trên.

SELECT TOP (1) 
[Extent1].[StudentID] AS [StudentID], 
[Extent1].[StudentName] AS [StudentName], 
[Extent1].[StandardId] AS [StandardId]
FROM [dbo].[Student] AS [Extent1]
WHERE 'Bill' = [Extent1].[StudentName]
Tip: bạn nên sử dụng phương thức FirstOrDefault thay cho phương thức First. Lý do là vì phương thức First sẽ ném ra ngoại lệ nếu truy vấn không có dữ liệu còn phương thức FirstOrDefault sẽ trả về null trong trường hợp này.

Truy vấn có tham số

Entity Framework (EF) xây dựng và thực thi một truy vấn có tham số trong cơ sở dữ liệu nếu truy vấn LINQ-to-Entities sử dụng các tham số, chẳng hạn như ví dụ bên dưới.

using (var ctx = new SchoolDBEntities())
{    
    string name = "Bill";
    var student = ctx.Students
                     .Where(s => s.StudentName == name)
                     .FirstOrDefault<Student>();
}

Truy vấn trên sẽ dẫn đến truy vấn SQL sau trong Entity Framework (EF) 6.

SELECT TOP (1) 
[Extent1].[StudentId] AS [StudentId], 
[Extent1].[Name] AS [Name]
FROM [dbo].[Student] AS [Extent1]
WHERE ([Extent1].[Name] = @p__linq__0) OR (([Extent1].[Name] IS NULL) 
         AND (@p__linq__0 IS NULL))',N'@p__linq__0 nvarchar(4000)',@p__linq__0=N'Bill'

Phương thức ToList()

Phương thức ToList trả về danh sách kết quả. Nếu bạn muốn liệt kê tất cả các sinh viên có cùng tên "Bill" thì hãy sử dụng phương thức ToList():

using (var ctx = new SchoolDBEntities())
{    
    var studentList = ctx.Students.Where(s => s.StudentName == "Bill").ToList();
}

Chúng ta cũng có thể sử dụng phương thức ToArray(), ToDictionary() hoặc ToLookup() để trả về danh sách kết quả. Truy vấn trên sẽ dẫn đến truy vấn SQL trong cơ sở dữ liệu như sau:

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

Phương thức GroupBy()

Sử dụng toán tử group by hoặc phương thức mở rộng GroupBy để lấy kết quả được nhóm theo thuộc tính cụ thể của một thực thể.

Ví dụ sau đây nhận được các kết quả được nhóm theo thuộc tính StandardId của thực thể Student. Sử dụng vòng lặp foreach để duyệt các phần tử trong nhóm như ví dụ dưới đây.

Cú pháp truy vấn LINQ:

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

    foreach (var groupItem in students)
    {
        Console.WriteLine(groupItem.Key);

        foreach (var stud in groupItem)
        {
            Console.WriteLine(stud.StudentId);
        }
    }
}

Cú pháp phương thức LINQ:

using (var ctx = new SchoolDBEntities())
{    
    var students = ctx.Students.GroupBy(s => s.StandardId);

    foreach (var groupItem in students)
    {
        Console.WriteLine(groupItem.Key);

        foreach (var stud in groupItem)
        {
            Console.WriteLine(stud.StudentId);
        }
    }
}

Truy vấn trên sẽ thực hiện truy vấn SQL trong cơ sở dữ liệu như sau:

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

Phương thức OrderBy()

Sử dụng toán tử order by với các từ khóa ascending (sắp xếp tăng dần) hoặc descending (sắp xếp giảm dần) trong cú pháp truy vấn LINQ để lấy danh sách thực thể được sắp xếp.

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

Sử dụng phương thức OrderBy (sắp xếp tăng dần) hoặc OrderByDescending (sắp xếp giảm dần) để có được danh sách thực thể được sắp xếp.

using (var ctx = new SchoolDBEntities())
{    
    var students = ctx.Students.OrderBy(s => s.StudentName).ToList();
    // or descending order  
    var  descStudents = ctx.Students.OrderByDescending(s => s.StudentName).ToList();
}

Truy vấn trên sẽ thực hiện truy vấn SQL trong cơ sở dữ liệu như sau:

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

Trả về anonymous object

Các truy vấn LINQ-to-Entities không phải luôn trả về các đối tượng thực thể. Chúng ta có thể chọn một số thuộc tính của một thực thể để trả về kết quả.

Truy vấn sau đây trả về một danh sách các đối tượng ẩn danh (anonymous object) có chứa các thuộc tính StudentIdStudentName.

Cú pháp truy vấn LINQ:

using (var ctx = new SchoolDBEntities())
{    
    var anonymousObjResult = from s in ctx.Students
                             where s.StandardId == 1
                             select new 
                             { 
                                Id = st.StudentId, 
                                Name = st.StudentName
                             };

    foreach (var obj in anonymousObjResult)
    {
        Console.Write(obj.Name);
    }
}

Cú pháp phương thức LINQ:

using (var ctx = new SchoolDBEntities())
{    
    var anonymousObjResult = ctx.Students
                                .Where(st => st.Standard == 1)
                                .Select(st => new 
                                { 
                                    Id = st.StudentId, 
                                    Name = st.StudentName 
                                });

    foreach (var obj in anonymousObjResult)
    {
        Console.Write(obj.Name);
    }
}

Truy vấn trên sẽ thực hiện truy vấn SQL trong cơ sở dữ liệu như sau:

SELECT 
[s].[StudentID] AS [Id], [s].[StudentName] AS [Name]
FROM [Student] AS [s]
WHERE [s].[StandardId] = 1
go

Các truy vấn lồng nhau

Bạn cũng có thể thực hiện các truy vấn LINQ-to-Entities lồng nhau như dưới đây:

Truy vấn lồng nhau được trình bày ở trên sẽ trả về một danh sách các đối tượng ẩn danh có chứa các thuộc tính StudentNameCourse.

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

Theo cách này, bạn có thể trả về bất kỳ dữ liệu gì mà bạn mong muốn.

Entity Framework
Bài Viết Liên Quan:
2 kịch bản lưu dữ liệu trong Entity Framework Core
Trung Nguyen 30/04/2020
2 kịch bản lưu dữ liệu trong Entity Framework Core

2 kịch bản lưu dữ liệu trong Entity Framework Core là kịch bản được kết nối và kịch bản ngắt kết nối.

Ứng dụng Entity Framework Core đầu tiên
Trung Nguyen 29/04/2020
Ứng dụng Entity Framework Core đầu tiên

Tạo ứng dụng .NET Core Console đầu tiên và cấu hình sử dụng Entity Framework Core.

Truy vấn trong Entity Framework Core
Trung Nguyen 29/04/2020
Truy vấn trong Entity Framework Core

Truy vấn trong Entity Framework Core có gì mới? Truy vấn trong EF Core khác EF ở những điểm nào.

Entity Framework Core toàn tập
Trung Nguyen 29/04/2020
Entity Framework Core toàn tập

Entity Framework Core toàn tập sẽ hướng dẫn bạn tất cả mọi thứ về Entity Framework Core.