Thực thi truy vấn LINQ

Có hai kịch bản thực thi truy vấn LINQ:

  • Trì hoãn thực thi truy vấn LINQ (Deferred Execution of LINQ Query).
  • Thực thi ngay lập tức truy vấn LINQ (Immediate Execution of LINQ Query).

Trì hoãn thực thi truy vấn LINQ

Trì hoãn thực thi là gì?

Trì hoãn thực thi có nghĩa là việc đánh giá một biểu thức bị trì hoãn cho đến khi giá trị thực sự của nó được yêu cầu.

Trì hoãn thực thi truy vấn LINQ giúp cải thiện đáng kể hiệu suất bằng cách tránh thực thi không cần thiết.

Việc trì hoãn thực thi được áp dụng trên mọi tập hợp trong bộ nhớ cũng như các trình cung cấp LINQ từ xa như LINQ-to-SQL, LINQ-to-Entities, LINQ-to-XML, v.v.

Hình ảnh đưới đây minh họa trì hoãn thực thi truy vấn LINQ:

Trì hoãn thực thi truy vấn LINQ

Trong ví dụ trên, bạn có thể thấy truy vấn được thực thi khi bạn thực hiện duyệt danh sách bằng vòng lặp foreach.

Điều này được gọi là trì hoãn thực thi.

LINQ xử lý danh sách studentList khi bạn thực sự truy cập từng đối tượng trong danh sách và làm một cái gì đó với nó.

Trì hoãn thực thi trả về dữ liệu mới nhất

Để kiểm tra xem việc trì hoãn thực thi có trả lại dữ liệu mới nhất mỗi lần hay không, hãy thêm một sinh viên tuổi teen sau vòng lặp foreach và kiểm tra danh sách teenAgerStudents như sau:

Trì hoãn thực thi truy vấn LINQ

Như bạn có thể thấy, vòng lặp foreach thứ hai thực hiện lại truy vấn và trả về dữ liệu mới nhất.

Việc trì hoãn thực thi sẽ thực hiện đánh giá lại trên mỗi lần thực thi; điều này được gọi là lazy evaluation. Đây là một trong những lợi thế chính của việc trì hoãn thực thi: nó luôn cung cấp cho bạn dữ liệu mới nhất.

Triển khai trì hoãn thực thi

Bạn có thể triển khai trì hoãn thực thi cho các phương thức mở rộng tùy chỉnh của mình cho interface IEnumerable bằng cách sử dụng từ khóa yield của C#.

Ví dụ: bạn có thể triển khai phương thức mở rộng tùy chỉnh GetTeenAgerStudents cho IEnumerable trả về danh sách tất cả học sinh là thanh thiếu niên.

public static class EnumerableExtensionMethods
{
    public static IEnumerable<Student> GetTeenAgerStudents(this IEnumerable<Student> source)
    {
        foreach (Student std in source)
        {
            Console.WriteLine("Accessing student {0}", std.StudentName);

            if (std.age > 12 && std.age < 20)
            {
                yield return std;
            }
        }
    }
}

Lưu ý rằng chúng tôi sẽ in tên sinh viên bất cứ khi nào phương thức GetTeenAgerStudents() được gọi.

Bây giờ bạn có thể sử dụng phương thức mở rộng này như dưới đây:

IList<Student> studentList = new List<Student>() 
{ 
    new Student() { StudentID = 1, StudentName = "John", age = 13 },
    new Student() { StudentID = 2, StudentName = "Steve", age = 15 },
    new Student() { StudentID = 3, StudentName = "Bill", age = 18 },
    new Student() { StudentID = 4, StudentName = "Ram", age = 12 },
    new Student() { StudentID = 5, StudentName = "Ron", age = 21 } 
};
            
var teenAgerStudents = from s in studentList.GetTeenAgerStudents() 
                       select s;

foreach (Student teenStudent in teenAgerStudents)
{
    Console.WriteLine("Student Name: {0}", teenStudent.StudentName);
}

Đây là kết quả khi biên dịch và thực thi chương trình:

Accessing student John
Student Name: John
Accessing student Steve
Student Name: Steve
Accessing student Bill
Student Name: Bill
Accessing student Ram
Accessing student Ron

Như bạn có thể thấy từ đầu ra, phương thức GetTeenAgerStudents() sẽ được gọi khi bạn duyệt studentList bằng cách sử dụng vòng lặp foreach.

Trì hoãn thực thi truy vấn LINQ

Vì vậy, theo cách này bạn có thể tạo các phương thức mở rộng tùy chỉnh bằng cách sử dụng từ khóa yield để có được lợi thế của việc trì hoãn thực thi.

Thực thi ngay lập tức truy vấn LINQ

Thực hiện ngay lập tức thì trái ngược với trì hoãn thực thì. Nó buộc truy vấn LINQ thực thi và nhận kết quả ngay lập tức. Các toán tử chuyển đổi To thực hiện truy vấn đã cho và đưa ra kết quả ngay lập tức.

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

Trong ví dụ sau, phương thức mở rộng ToList() thực hiện truy vấn ngay lập tức và trả về kết quả.

IList<Student> teenAgerStudents = studentList
    .Where(s => s.age > 12 && s.age < 20)
    .ToList();

Cú pháp truy vấn

var teenAgerStudents = from s in studentList
                       where s.age > 12 && s.age < 20
                       select s;

Các truy vấn trên sẽ không thực hiện ngay lập tức. Bạn sẽ không tìm thấy bất kỳ kết quả nào như hình dưới đây:

Thực thi ngay lập tức truy vấn LINQ

Cú pháp truy vấn không hỗ trợ toán tử 'To' nhưng có thể sử dụng phương thức ToList(), ToArray() hoặc ToDictionary() để thực thi ngay lập tức như dưới đây:

IList<Student> teenAgerStudents = (from s in studentList
                                   where s.age > 12 && s.age < 20
                                   select s).ToList();

Bạn có thể xem kết quả trong danh sách teenAgerStudents như sau:

Thực thi ngay lập tức truy vấn LINQ


Bài viết liên quan:

Bạn sẽ tìm hiểu một số truy vấn LINQ phức tạp trong hướng dẫn này.

Từ khóa let, into trong LINQ có tác dụng gì? Hướng dẫn khai báo và sử dụng từ khóa let, into trong LINQ.

Expression trong LINQ

  • 11 min read

Expression trong LINQ là gì? Cây biểu thức trong LINQ là gì? Cách khai báo và sử dụng chúng trong LINQ.