Trong bài viết, chúng ta sẽ tìm hiểu các câu truy vấn cơ bản nhất trong LINQ. Các câu lệnh nâng cao trong LINQ chúng ta sẽ tìm hiểu trong các bài tiếp theo.
Lấy một nguồn dữ liệu
Trong truy vấn LINQ, bước đầu tiên là đặc tả nguồn dữ liệu. Mệnh đề from phải có đầu tiên để mô tả nguồn dữ liệu (customers) và biến phạm vi (cust).
//queryAllCustomers là 1 biến có kiểu dữ liệu IEnumerable<Customer> - dammio.com var queryAllCustomers = from cust in customers select cust;
Để lấy dữ liệu 1 trường (ví dụ tên khách hàng FullName) trong danh sách khách hàng (Customer) thì làm như sau:
// Lấy tên đầy đủ FullName var queryAllCustomers = from cust.FullName in customers select cust;
Biến phạm vi (range variable) giống như biến lặp trong vòng lặp foreach ngoại trừ không có vòng lặp nào xảy ra trong 1 diễn giải truy vấn. Khi truy vấn được thực thi, biến phạm vi sẽ đóng vai trò là 1 tham chiếu với mỗi phần tử tiếp theo trong customers. Bởi vì trình biên dịch có thể suy luận dạng của cust, vì vậy chúng ta không cần phải đặc tả kiểu dữ liệu cho cust rõ ràng. Thêm nữa các biến phạm vi có thể được giới thiệu bằng mệnh đề let. Bạn có thể tìm hiểu thêm về mệnh đề let ở https://msdn.microsoft.com/en-us/library/bb383976.aspx.
Lọc dữ liệu (Filter)
Lọc dữ liệu là câu lệnh truy vấn phổ biến ở dạng diễn giải Boolean (đúng hoặc sai). Câu truy vấn chỉ trả về các phần tử nếu diễn giải là đúng (true). Để lọc dữ liệu, chúng ta dùng mệnh đề where, trong đó mô tả các điều kiện lọc.
var queryLondonCustomers = from cust in customers where cust.City == "Đà Lạt" select cust;
Trong câu truy vấn ở ví dụ trên, chúng ta tìm những khách hàng (customers) ở thành phố ở “Đà Lạt”. Bạn có dùng các toán tử AND và OR trong C# để áp dụng các diễn giải lọc cần thiết trong mệnh đề where. Ví dụ tiếp theo, để tìm các khách hàng ở thành phố Đà Lạt và có tên là “Dammio” chúng ta có thể viết đoạn mã sau:
//Tìm các khách hàng ở Đà Lạt và có tên là Dammio var queryLondonCustomers = from cust in customers where cust.City == "Đà Lạt" && cust.FullName == "Dammio" select cust; //Tìm các khách hàng ở Đà Lạt hoặc có tên là Dammio var queryLondonCustomers1 = from cust in customers where cust.City == "Đà Lạt" || cust.City == "Dammio" select cust;
Sắp xếp (order)
Mệnh đề orderby cho phép sắp xếp các phần tử theo thứ tự nào đó trong dữ liệu trả về. Để sắp xếp trường Name (tên) theo thứ tự alphabet với các khách hàng ở Đà Lạt, chúng ta có thể làm như ví dụ sau:
var queryLondonCustomers3 = from cust in customers where cust.City == "Đà Lạt" orderby cust.Name ascending select cust;
Để sắp xếp ngược lại, bạn có thể dùng mệnh đề descending. Ví dụ tiếp theo mô tả cách sắp xếp tăng theo trường Name (tên), và sau đó sắp giảm theo trường Birthday (ngày sinh) của các khách hàng ở Đà Lạt.
var queryLondonCustomers3 = from cust in customers where cust.City == "Đà Lạt" orderby cust.Name ascending, cust.Birthday descending select cust;
Gom nhóm (group)
Mệnh đề group cho phép gom nhóm kết quả dựa trên 1 khóa được mô tả. Ví dụ, chúng ta muốn gom nhóm các khách hàng từ Đà Lạt theo thành phố (City), trong trường hợp này cust.City được gọi là khóa.
// queryCustomersByCity là 1 IEnumerable<IGrouping<string, Customer>> var queryCustomersByCity = from cust in customers group cust by cust.City; // gom theo thành phố // customerGroup là 1 IGrouping<string, Customer> foreach (var customerGroup in queryCustomersByCity) { Console.WriteLine(customerGroup.Key); foreach (Customer customer in customerGroup) { Console.WriteLine(" {0}", customer.Name); } }
Nếu thực hiện 1 câu truy vấn trong 1 mệnh đề group, kết quả là dạng 1 danh sách lồng 1 danh sách. Mỗi phần trong danh sách là 1 phần tử có 1 thành phần khóa và 1 danh sách các phần tử được gom nhóm theo khóa đó. Chúng ta có thể dùng vòng lặp foreach để lấy các nhóm khách hàng theo thành phố, trong mỗi nhóm đó lại lấy xuất ra tên của từng khách hàng như ví dụ trên. Ví dụ trên có kết quả như dưới đây:
Đà Lạt Nguyễn Văn Anh Trịnh Thị Chung Hoàng Phan Nha Trang Phan Văn Tiến Lê Công Minh Đà Nẵng Dammio Ta John Adam
Ví dụ tiếp theo hiển thị tên các nhóm thành phố nếu chứa hơn 2 khách hàng.
// custQuery is an IEnumerable<IGrouping<string, Customer>> var custQuery = from cust in customers group cust by cust.City into custGroup where custGroup.Count() > 2 orderby custGroup.Key select custGroup;
Kết hợp (join)
Tương tự như SQL, kết hợp (join) dữ liệu xảy ra giữa các tập đối tượng dữ liệu mà chưa được mô hình rõ ràng trong nguồn dữ liệu. Ví dụ, chúng ta tìm tất cả khách hàng (customers) và các nhà phân phối (distributors) ở cùng thành phố. Mệnh đề join trong LINQ cho phép kết hợp dữ liệu trên các tập đối tượng theo vì dùng bảng cơ sở dữ liệu trực tiếp.
var innerJoinQuery = from cust in customers join dist in distributors on cust.City equals dist.City select new { CustomerName = cust.Name, DistributorName = dist.Name };
Trong ví dụ trên, chúng ta join 2 tập dữ liệu customers và distributors trên trường City sau đó xuất ra tập dữ liệu chứa CustomerName và DistributorName.
Trong LINQ, chúng ta không cần phải dùng mệnh đề join thường xuyên như trong SQL bởi vì các khóa ngoại trong LINQ thông thường được mô tả trong mô hình đối tượng (object model) như là các thuôc tính liên kết 1 tập các phần tử. Ví dụ, một đối tượng Customer chứa 1 tập các đối tượng Order. Thay vì dùng join, chúng ta có thể truy xuất danh sách orders bằng dấu chấm.
from order in Customer.Orders ...
Chọn các trường dữ liệu (select)
Mệnh đề select dùng để chọn các dạng giá trị làm kết quả trả về trong 1 truy vấn LINQ.
//Tạo nguồn dữ liệu List<int> Scores = new List<int>() { 9, 92, 811, 44, 55 }; // Tạo câu truy vấn IEnumerable<int> queryHighScores = from score in Scores where score > 80 select score; // Thực hiện truy vấn foreach (int i in queryHighScores) { Console.Write(i + " "); }
Trong ví dụ trên, chúng ta thấy mệnh đề select được dùng để chọn các điểm (score) với điều kiện score > 80 và hiển thị kết quả trên màn hình Console. Để chọn hết tất cả thuộc tính dữ liệu của đối tượng trong dữ liệu nguồn, chúng ta có thể làm như ví dụ sau:
var studentQuery = from s in Students where s.ID > 111 select s;
Trong ví dụ trên chúng ta sử dụng select s với s là 1 phần tử trong danh sách Students, khi đó câu lệnh sẽ chọn hết tất cả thuộc tính của 1 sinh viên bao gồm s.ID, s.Name, s.Birthday, … và câu lệnh này tương tự như select * trong SQL.
Ngoài ra để chọn 1 vài thuộc tính dữ liệu của các đối tượng nhưng không chọn hết tất cả các thuộc tính chúng ta có thể sử dụng select new.
var studentQuery = from s in Students where s.ID > 111 select new ScoreInfo { Average = student.Scores.Average(), ID = s.ID };
Trong ví dụ, chúng ta chọn những sinh viên có ID > 111 và sau đó xuất ra thông tin điểm của từng sinh viên ở đối tượng ScoreInfo gồm 2 thuộc tính mới: Average (điểm trung bình của sinh viên) và ID của sinh viên đó.
Kết luận: Bài viết đã trình bày các truy vấn cơ bản trong LINQ. Tuy nhiên, nắm vững các truy vấn này vẫn chưa đủ cho bạn làm việc với LINQ ở nhiều dự án và môi trường thực tế. Bạn cần phải biết cách kết hợp các truy vấn này và học thêm nhiều các câu truy vấn nâng cao nữa để đáp ứng nhu cầu.
Vui lòng trích dẫn địa chỉ website nếu sao chép hoặc tổng hợp thông tin từ website này.
- APA:
Dammio. (2016). [LINQ] Phần 3: Các truy vấn cơ bản trong LINQ. https://www.dammio.com/2016/12/17/linq-phan-3-cac-truy-van-co-ban-trong-linq.
- BibTeX:
@misc{dammio,
author = {Dammio},
title = {[LINQ] Phần 3: Các truy vấn cơ bản trong LINQ},
year = {2016},
url = {https://www.dammio.com/2016/12/17/linq-phan-3-cac-truy-van-co-ban-trong-linq},
urldate = {2024-12-05}
}
cảm ơn tác giả, tôi đã học được nhiều từ bài này
cho em hỏi tác giả ! là nếu em muốn truy vấn dữ liệu lần lượt 3 hoặc 4 bảng dữ liệu khác nhau giống SQL mình phải làm như thế nào vậy tác giả ?
—- em cảm ơn tác giả ạ
form a in table_a
join b in table_b on a.IDa equal b.IDb
where …
select new{
a.ID,
a.Name,
b.Name
}