2. Nội dung
• Tổng quan Linq
• Các kỹ thuật Linq sử dụng
• Delegate và Generic Delegate
• IEnumrable và Yield
• Lambda Expression
• Extension method
• Câu lệnh truy vấn Linq
Lập trình .Net 2
4. Language Integrated Query
• LinQ là một thư viện cung cấp cho ngôn ngữ lập trình C# và Visual Basic trong
.NET Framework 3.5.
• LinQ hỗ trợ truy vấn dữ liệu từ nhiều nguồn khác nhau: XML, SQL, …
• LinQ mô hình hóa database thành các class, từ đó ta có thể truy xuất database
thông qua những class đó.
• LinQ giúp cho lập trình viên dễ dàng truy xuất dữ liệu ngay trên ngôn ngữ lập
trình.
• Do truy xuất trên ngôn ngữ lập trình nên dễ dàng debug lỗi.
Lập trình .Net 4
5. Các kỹ thuật sử dụng trong Linq
• Delegate
• Generic Delegate
• Lambda Expression
• IEnumrable
• Extension method
Lập trình .Net 5
6. Delegate
• Deledate trong tương ứng với con trỏ hàm trong C/C++
• Là một biến tham chiếu đến một phương thức mà có cùng nguyên mẫu
với delegate
Lập trình .Net 6
static void Main(string[] args){
Program p = new Program();
AddDelegate a = p.Add; //gọi hàm Add thông qua delegate
Console.WriteLine("" + a(1, 2));//3
}
public delegate int AddDelegate(int x, int y); //khai báo delegate
public int Add(int x, int y) { return x + y; };
7. Delegate
• Vì là một biến nên ta có thể truyền vào phương thức như một
tham số
Lập trình .Net 7
static void Main(string[] args) {
Program p = new Program();
p.sayHello(p.Hello); //truyền vào phương thức Hello
} //Hello: My delegate
public delegate void HelloDelegate(String str);
//<Phạm_vi> delegate <kiểu_trả_về> <tên_delegate> <tham_số>
public void Hello(String str) {
Console.Write("Hello: " + str);
}
public void sayHello(HelloDelegate doSomeThing) {
var str = "My delegate";
doSomeThing(str);
}
8. Delegate
• Các cách khai báo delegate:
• Action: Action<T in1, T in2, …> = delegate void<in 1, in2, ….>
//trả về void có nhiều tham số đầu vào
• Predicate: Predicate<T in> = delegate bool<in1>
//trả về bool, có 1 tham số
• Func: Func<T in1, T in2, … ,T result> = delegate <kiểu _giá_trị> <in1,in2,...>
//bắt buộc phải có giá trị trả về, có nhiều tham số
Lập trình .Net 8
9. Generic delegate
• Generic là một kiểu dữ liệu “tự do” để định nghĩa cho kiểu dữ liệu trả về hoặc tham số của phương thức
hoặc class.
• Generic giúp cho phương thức có thể làm việc với nhiều kiểu dữ liệu khác nhau =>tối đa hóa việc tái sử
dụng được code
Lập trình .Net 9
public delegate T AddDelegate<T>(T x, T y);
//khai báo generic delegate
Generic
AddDelegate<int> a = Add;
//Generic được định nghĩa khi phương thức được sử dụng
Console.WriteLine("" + a(1, 2));//3
10. Lambda Expression
• Khi phương thức được tham chiếu chỉ sử dụng một lần thì không cần thiết khai báo
phương thức
• Để đơn giản hóa câu lệnh ta có thế sử dụng anonymous method
Lập trình .Net 10
AddDelegate<int> a = delegate(int x, int y) {return x + y;};
// anonymous method
AddDelegate<int> a = (x, y) => { return x + y; };
// “=>” là toán tử Lambda
AddDelegate<int> a = (x, y) => (x + y);
//bỏ kiểu dữ liệu tham số,
//bỏ {} nếu chỉ có 1 câu lệnh,
//bỏ return nếu trả về 1 giá trị
//bỏ () nếu chỉ có 1 tham số
11. IEnumrable và Yield Return
• IEnumerable là một mảng dữ liệu chỉ đọc, không cho phép thêm xóa, chỉ duyệt 1 chiều từ đầu đến cuối
bằng lệnh foreach.
• Phương thức trả về kiểu dữ liệu là IEnumerable<T>; yield return trả về 1 phần tử của mảng IEnumerable
mỗi khi phương thức đó được gọi.
Lập trình .Net 11
foreach (int i in Numbers(10).Take(3)) {
Console.WriteLine("Number {0}", i);
//Với yield return Numbers duyệt từng phần tử sau đó in ra màn hình
//chỉ duyệt đến phần tử thứ 3 không cần duyệt hết tất cả phần tử
}
IEnumerable<int> Numbers(int max) {
for (int i = 0; i < max; i++) {
yield return i;
}
}
12. IEnumrable và Yield Return
• Phương thức Numbers() chỉ được chạy khi muốn trả về kết
quả, sau đó dừng lại cho đến khi muốn trả về một phần tử tiếp
theo và nếu không cần trả về kết quả thêm nữa phương thức
sẽ kết thúc mà không cần duyệt hết tất cả các phần tử trong
mảng.
• So với kiểu duyệt mảng thông thường:
Hiệu năng cao hơn
Tốn ít bộ nhớ hơn
Giải quyết được bài toán duyệt mảng có số phần tử lớn hoặc vô hạn
số phần tử.
Lập trình .Net 12
13. Extension method
• Extension method giúp tạo thêm các phương thức cho một lớp mà không cần
thừa kế lại lớp đó.
• Lớp chứa extension method phải là static
• Extension method cũng phải là một phương thức static
• Từ khóa this đặt trước tham số đầu vào
• Cần khai báo để sử dụng ở namespace khác
Lập trình .Net 13
public static class PrintInt {
public static void PrintX(this int x) => Console.WriteLine(x.ToString());
}
//gọi hàm PrintX in ra màn hình số x
int x = 1996;
x.PrintX();
14. Kiểu Nullable
• Các kiểu dữ liệu int, bool, DateTime,… không thể gán giá trị null
• Truy xuất SQL lại thường xuất hiện giá trị null
• C# cung cấp kiểu Nullable cho phép nhưng biến tham trị có thể gán được giá trị null
• Khai báo
< kiểu_dữ_liệu > ? <tên_biến> = null;
Lập trình .Net 14
int? x = null; //khai báo nullable
bool b = x.HasValue; //kiểm tra biến đã được gán giá trị
int i = x.GetValueOrDefault(); //lấy giá trị hoặc giá trị mặc định
15. Tự viết LinQ
• Linq là 1 danh sách các extension method, thêm một số phương thức cho interface
IENumerable
Lập trình .Net 15
public static class MyLinQ {
public static IEnumerable<T> Where<T>(IEnumerable<T> items, Func<T, bool> func) {
//tự tạo câu truy vấn Where trong LinQ
foreach (var item in items) {
if(func(item)) {
yield return item;
}
}
}
}
Delegate
Kiểu Ienumerable
và yield
16. Truy vấn LinQ
• LinQ hỗ trợ 2 cách truy vấn dữ liệu:
• Truy vấn bằng các phương thức
• Truy vấn bằng từ khóa
Lập trình .Net 16
var querySV = from sv in SinhVien //truy vấn bằng các từ khóa
where sv.Diem == "A"
orderby sv.Name
select sv;
//truy vấn bằng các phương thức
var queryOperator = SinhVien.Where(sv => sv.Diem == "A")
.OrderBy(sv => sv.Name);
• Hai cách truy vấn trên có hiệu năng như nhau
• Có thể kết hợp 2 cách viết trong cùng 1 câu lệnh
17. Quy tắc viết cú pháp truy vấn
• Mệnh đề from phải có đầu tiên để mô tả nguồn dữ liệu và biến phạm vi
• Kết thúc bằng select hoặc group by
• Ở giữa: where, orderby, join, let, into, from …
Lập trình .Net 17
var query = (from num in numbers //kết hợp 2 cách truy vấn
where num % 2 == 0
select num)
.OrderBy(n=>n);
18. Let và Select many
• Từ khóa let sử dụng để khai báo 1 biến trong khi truy vấn
Lập trình .Net 18
var query = from sv in sinhvien
let name = sv.name
where name == "sang"
select sv;
• Select many tham chiếu đến tất cả các tập con của tập dữ liệu cha
List<string> line = new List<string>() { "welcome to", "microsoft studio linq",
"visual" };
// Lấy ra từng chữ cái bằng keywords
var query = from words in line
from word in words.Split(' ‘)
select word;
// Lấy ra từng chữ cái bằng operators
var queryOpera = line.SelectMany(x => x.Split(' '));
19. Group – gom nhóm
• Mệnh đề group cho phép gom nhóm kết quả dựa trên 1 khóa được mô tả
• Group kết hợp với into, tạo một biến mới đại diện cho từng nhóm và có thế thao
tác(sortting, filtering, …) trên từng nhóm.
Lập trình .Net 19
//lấy ra nhóm chứa các số lẻ
//truy vấn bằng từ khóa
var query = from number in numbers
group number by number % 2 into g
where g.Key == 1
select g;
//truy vấn bằng các phương thức
var querry = numbers.GroupBy(n => n % 2).Where(g => g.Key == 1);
20. Join – Kết nối
• Join: kết nối 2 nguồn dữ liệu dựa trên một khóa
chung
Lập trình .Net 20
//lấy ra inner join
var joinQuery = from sv in sinhvien
join info in infomationSV
on sv.ID equals info.ID
select new { sv.name, info};
//Kết nối lớp sản phẩm và lớp danh mục, nếu CategoryID không tồn tại ở lớp danh mục thì đặt
CategoryName giá trị là “Unknown”
var query1 = from product in listProducts
join category in listCategories
on product.CategoryID equals category.CategoryID into temp
from subtemp in temp.DefaultIfEmpty() //outer join default = null
select new {product.ProductName, product.CategoryID,
CategoryName = subtemp == null ? "Unknown" : subtemp.CategoryName };
21. Select a single item
• Single lấy ra một phần tử trong khi truy vấn
• SingleOrDefault trả về null nếu không có giá trị thỏa mãn
Lập trình .Net 21
int query = numbers.SingleOrDefault(x => x > 100);
//tìm kiếm lấy ra 1 số có giá trị lớn hơn 100
// không tìm thấy, trả về mặc định là query = 0
22. Caching – lưu trữ
• LinQ có hỗ trợ hàm ToArray và ToList lưu trữ kết quả truy vấn dưới dạng Array và List
• Sau khi gọi 2 hàm trên câu lệnh truy vấn được thực thi và kết thúc ngay sau khi hoàn thành
• ToDictionary lưu trữ dưới dạng Dictionary dựa trên 1 hàm chọn khóa
Lập trình .Net 22
//luu tru ket qua truy van
int[] result = numbers.ToArray();
List<int> result = numbers.ToList();
//key la ID
Dictionary<int, string> result = sinhvien.ToDictionary(x => x.ID);
23. Toán tử tổng hợp
• Trả về 1 giá trị từ tập các giá trị
• Tính trung bình
• Tính tổng
• Tính số lượng
• Tính min, max
Lập trình .Net 23
int count = numbers.Count();
int sum = numbers.Sum();
int min = numbers.Min();
int max = numbers.Max();
double average = numbers.Average();