Bài 17: Giới thiệu nhanh về LINQ - Truy vấn dữ liệu thanh lịch như viết SQL
🎯 Mục tiêu bài học
-
Hiểu khái niệm LINQ và biểu thức Lambda (
=>). -
Thay thế các vòng lặp
foreachdài dòng bằng các câu lệnh LINQ 1 dòng. -
Nắm vững 5 hàm LINQ quan trọng nhất mà một Backend Developer dùng hàng ngày:
Where,Select,FirstOrDefault,OrderBy, vàAny.
📖 Phần 1: LINQ là gì? Tại sao nó là "vũ khí tối thượng"?
LINQ (Language Integrated Query) là một công cụ tích hợp sẵn trong C# giúp bạn truy vấn dữ liệu (tìm kiếm, lọc, sắp xếp, biến đổi) từ các danh sách (List, mảng) cực kỳ mạnh mẽ và ngắn gọn, giống hệt như cách bạn viết SQL để truy vấn Database.
Hãy xem sự khác biệt khi muốn lấy ra các số chẵn từ một mảng:
Cách cũ (Dùng foreach):
C#
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6 };
List<int> evenNumbers = new List<int>();
foreach (int num in numbers)
{
if (num % 2 == 0)
{
evenNumbers.Add(num);
}
}
Cách mới (Dùng LINQ - Chỉ 1 dòng):
C#
using System.Linq; // Bắt buộc phải có thư viện này
// Đọc là: Trong list numbers, lọc (Where) lấy các phần tử 'x' sao cho 'x' chia hết cho 2.
List<int> evenNumbers = numbers.Where(x => x % 2 == 0).ToList();
Ký hiệu x => ... được gọi là Biểu thức Lambda (Lambda Expression). Chữ x chỉ là một tên biến tạm tự đặt (bạn có thể đặt là n, item, p tùy ý), đại diện cho từng phần tử khi LINQ duyệt qua danh sách.
📖 Phần 2: 5 Hàm LINQ "cốt tử" cho Backend
Giả sử chúng ta có một danh sách sản phẩm:
C#
record Product(int Id, string Name, double Price);
List<Product> products = new List<Product>
{
new Product(1, "Laptop", 25000000),
new Product(2, "Mouse", 300000),
new Product(3, "Keyboard", 1500000),
new Product(4, "Monitor", 4000000)
};
1. Where (Lọc dữ liệu)
Giống mệnh đề WHERE trong SQL. Dùng để lấy ra một danh sách mới thỏa mãn điều kiện.
C#
// Lấy các sản phẩm có giá trên 1 triệu
var expensiveProducts = products.Where(p => p.Price > 1000000).ToList();
2. FirstOrDefault (Tìm 1 phần tử đầu tiên)
Khác với Where trả về một danh sách, FirstOrDefault chỉ trả về 1 object duy nhất hoặc trả về null nếu không tìm thấy. Rất hay dùng để tìm user theo ID.
C#
// Tìm sản phẩm có Id = 2
var mouse = products.FirstOrDefault(p => p.Id == 2);
3. OrderBy / OrderByDescending (Sắp xếp)
Dùng để sắp xếp tăng dần hoặc giảm dần.
C#
// Sắp xếp giá từ cao xuống thấp
var sortedProducts = products.OrderByDescending(p => p.Price).ToList();
4. Select (Biến đổi dữ liệu / Ánh xạ)
Giống mệnh đề SELECT trong SQL. Dùng để "nhặt" ra một vài trường cụ thể, hoặc biến đổi từ kiểu dữ liệu này sang kiểu dữ liệu khác (như map từ Entity sang DTO).
C#
// Chỉ lấy ra danh sách tên của các sản phẩm (List<string>)
List<string> productNames = products.Select(p => p.Name).ToList();
5. Any (Kiểm tra tồn tại)
Trả về true hoặc false. Dùng để check xem có phần tử nào thỏa mãn điều kiện không, chạy cực nhanh vì nó sẽ dừng lại ngay khi tìm thấy phần tử đầu tiên hợp lệ.
C#
// Kiểm tra xem có sản phẩm nào giá dưới 100k không?
bool hasCheapItem = products.Any(p => p.Price < 100000); // Kết quả: false
💻 Phần 3: Thực hành (Chaining LINQ)
Bạn hoàn toàn có thể nối (chain) các hàm LINQ lại với nhau để thực hiện các truy vấn phức tạp trên một luồng duy nhất:
C#
using System;
using System.Collections.Generic;
using System.Linq; // Đừng quên using System.Linq
namespace Lesson17
{
record Student(string Name, double Gpa);
class Program
{
static void Main(string[] args)
{
List<Student> classA = new List<Student>
{
new Student("Hieu", 3.8),
new Student("An", 2.5),
new Student("Binh", 3.9),
new Student("Cuong", 3.2)
};
// Yêu cầu: Tìm những sinh viên có GPA > 3.0, sắp xếp điểm từ cao xuống thấp,
// và chỉ lấy ra danh sách tên của họ.
List<string> topStudentNames = classA
.Where(s => s.Gpa > 3.0) // Bước 1: Lọc điểm > 3.0
.OrderByDescending(s => s.Gpa) // Bước 2: Sắp xếp giảm dần
.Select(s => s.Name) // Bước 3: Chỉ lấy ra Tên
.ToList(); // Bước 4: Đóng gói thành List
Console.WriteLine("--- DANH SACH SINH VIEN XUAT SAC ---");
foreach (string name in topStudentNames)
{
Console.WriteLine($"- {name}");
}
// Kết quả in ra: Binh, Hieu, Cuong
Console.ReadLine();
}
}
}
🛠 Bài tập thực hành
Yêu cầu: Xử lý danh sách Đơn hàng (Order).
-
Tạo một
record Order(int OrderId, string CustomerName, double Total, bool IsDelivered); -
Tạo một
List<Order>gồm 4 đơn hàng với các trạng thái giao hàng (IsDelivered) khác nhau. -
Dùng LINQ thực hiện các yêu cầu sau:
-
Lấy ra danh sách các đơn hàng chưa được giao (
IsDelivered == false). -
Lấy ra đơn hàng duy nhất có
OrderId == 1(DùngFirstOrDefault). -
In các kết quả tìm được ra màn hình để kiểm chứng.
-
Đây là kỹ năng cốt lõi làm nền tảng cho việc sử dụng Entity Framework Core để truy vấn Database sau này.
All rights reserved