Truy vấn LINQ
Giới thiệu về truy vấn LINQ
Một truy vấn là một biểu thức lấy ra dữ liệu từ một nguồn dữ liệu. Các truy vấn thường được thể hiện bằng ngôn ngữ truy vấn chuyên biệt. Các ngôn ngữ khác nhau đã được phát triển theo thời gian cho các loại nguồn dữ liệu khác nhau, ví dụ SQL cho cơ sở dữ liệu quan hệ và XQuery cho XML. Do đó, các nhà phát triển đã phải học một ngôn ngữ truy vấn mới cho từng loại nguồn dữ liệu hoặc định dạng dữ liệu mà họ phải hỗ trợ. LINQ đơn giản hóa tình huống này bằng cách cung cấp mô hình nhất quán để làm việc với dữ liệu qua nhiều loại nguồn và định dạng dữ liệu khác nhau. Trong một truy vấn LINQ, bạn luôn làm việc với các đối tượng. Bạn sử dụng các mẫu mã cơ bản giống nhau để truy vấn và chuyển đổi dữ liệu trong các tài liệu XML, cơ sở dữ liệu SQL, bộ dữ liệu ADO.NET, các bộ sưu tập .NET và bất kỳ định dạng nào khác mà nhà cung cấp LINQ sẵn có.
Các phần của một thao tác truy vấn
Tất cả các thao tác truy vấn LINQ chứa ba phần phân biệt sau:
- Lấy nguồn dữ liệu
- Tạo truy vấn
- Thực thi truy vấn
Ví dụ LINQDemo sau sẽ minh hoạ cụ thể điều này:
Hình minh họa sau đây cho thấy hoạt động truy vấn hoàn chỉnh. Trong LINQ việc thực hiện truy vấn khác với truy vấn chính nó; nói cách khác bạn đã không lấy ra bất kỳ dữ liệu chỉ bằng cách tạo ra một biến truy vấn.
Nguồn dữ liệu
Trong ví dụ trước, vì nguồn dữ liệu là một mảng, nó ngầm hỗ trợ giao diện chung IEnumerable <T>. Thực tế này có nghĩa là nó có thể được truy vấn với LINQ. Một truy vấn được thực hiện trong một câu lệnh foreach, và foreach yêu cầu IEnumerable hoặc IEnumerable <T>. Các loại hỗ trợ IEnumerable <T> hoặc một interface có nguồn gốc như IQueryable chung <T> được gọi là các kiểu queryable.
Một kiểu queryable không yêu cầu sửa đổi hoặc điều trị đặc biệt để phục vụ như một nguồn dữ liệu LINQ. Nếu nguồn dữ liệu chưa có trong bộ nhớ như một kiểu queryable, thì nhà cung cấp LINQ phải đại diện nó như vậy. Ví dụ: LINQ to XML nạp một tài liệu XML vào một kiểu XElement có thể truy vấn:
// Create a data source from an XML document using System.Xml.Linq; XElement contacts = XElement.Load(@"c:\myContactList.xml");
Với LINQ to SQL, trước tiên bạn tạo một ánh xạ quan hệ đối tượng trong thời gian thiết kế bằng tay hoặc bằng cách sử dụng các công cụ LINQ to SQL trong Visual Studio trong Visual Studio. Bạn viết các truy vấn của bạn đối với các đối tượng, và tại thời gian chạy LINQ to SQL xử lý các giao tiếp với cơ sở dữ liệu. Trong ví dụ sau, Khách hàng thể hiện một bảng cụ thể trong cơ sở dữ liệu, và loại kết quả truy vấn, IQueryable <T> xuất phát từ IEnumerable <T>.
Northwnd db = new Northwnd(@"c:\northwnd.mdf"); // Query for customers in London. IQueryable<Customer> custQuery = from cust in db.Customers where cust.City == "London" select cust;
Lọc dữ liệu
Có lẽ hoạt động truy vấn phổ biến nhất là áp dụng bộ lọc dưới dạng biểu thức Boolean. Bộ lọc làm cho truy vấn chỉ trả về các phần tử mà biểu thức là đúng. Kết quả được tạo ra bằng cách sử dụng mệnh đề where. Bộ lọc có hiệu lực xác định các phần tử nào cần loại trừ khỏi chuỗi nguồn. Trong ví dụ sau, chỉ những khách hàng có địa chỉ ở London mới được trả lại.
var queryLondonCustomers = from cust in customers where cust.City == "London" select cust;
Bạn có thể sử dụng toán tử lôgíc AND và OR hợp lý quen thuộc để áp dụng nhiều biểu thức lọc nếu cần trong mệnh đề where. Ví dụ: chỉ trả lại khách hàng từ "London" VÀ có tên là "Devon" bạn sẽ viết đoạn mã sau:
where cust.City=="London" && cust.Name == "Devon" or where cust.City == "London" || cust.City == "Paris"
Sắp xếp dữ liệu
Thường thì thuận tiện để sắp xếp dữ liệu trả về. Mệnh đề orderby sẽ làm cho các phần tử trong chuỗi trả về được sắp xếp theo trình so sánh mặc định cho kiểu được sắp xếp. Ví dụ, truy vấn sau đây có thể được mở rộng để sắp xếp kết quả dựa trên thuộc tính Tên. Bởi vì Tên là một chuỗi, comparer mặc định thực hiện một sắp xếp theo thứ tự chữ cái từ A đến Z.
var queryLondonCustomers = from cust in customers where cust.City == "London" orderby cust.Name ascending select cust;
Nhóm dữ liệu
Mệnh đề nhóm cho phép bạn nhóm các kết quả của bạn dựa trên khóa mà bạn chỉ định. Ví dụ bạn có thể chỉ định rằng các kết quả nên được nhóm lại bởi Thành phố để tất cả khách hàng từ London hoặc Paris nằm trong các nhóm cá nhân. Trong trường hợp này, cust.City là chìa khóa.
// queryCustomersByCity is an IEnumerable<IGrouping<string, Customer>> var queryCustomersByCity = from cust in customers group cust by cust.City; // customerGroup is an IGrouping<string, Customer> foreach (var customerGroup in queryCustomersByCity) { Console.WriteLine(customerGroup.Key); foreach (Customer customer in customerGroup) { Console.WriteLine(" {0}", customer.Name); } }
Khi bạn kết thúc một truy vấn với mệnh đề nhóm, kết quả của bạn có dạng một danh sách các danh sách. Mỗi phần tử trong danh sách là một đối tượng có một thành viên chính và một danh sách các phần tử được nhóm lại dưới khóa đó. Khi bạn lặp lại một truy vấn tạo ra một dãy các nhóm, bạn phải sử dụng một vòng lặp foreach lồng nhau. Vòng ngoài lặp đi lặp lại qua mỗi nhóm, và vòng lặp bên trong iterates qua các thành viên của mỗi nhóm.
Nếu bạn phải tham khảo kết quả của một hoạt động nhóm, bạn có thể sử dụng từ khoá vào để tạo ra một định danh có thể được truy vấn thêm. Truy vấn sau chỉ trả lại những nhóm có chứa nhiều hơn hai 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;