- vừa được xem lúc

Khi nào sử dung LinQ <query> tốt hơn dùng LinQ <method>

0 0 12

Người đăng: Thang Le

Theo Viblo Asia

Thật lòng mà nói, LinQ vô cùng bá đạo, mạnh mẽ linh hoạt và đẹp đẽ. Mình yêu nó ngay từ cái nhìn đầu tiên, mình nghĩ các bạn cũng sẽ như vậy thôi 😄. Nếu tưởng tượng LinQ với một thứ gì đó ngoài đời thường, thì mình nghĩ ngay tới một chiếc smartphone - không ai phủ nhận tầm quan trọng của nó đúng không nào - mặc định là vậy đi.

LinQ có hai cách viết, một là viết kiểu query (kiểu này giống giống sql, team mình dùng cái tên LinQ sql :v), hai là viết kiểu method hoặc gọi là lambda. Vậy bây giờ chúng ta có câu hỏi: nên sử dụng linq method hay linq query? ai tốt hơn, cũng như cách sử dụng linq query với method như thế nào.

Ví dụ:

var numbers = Enumerable.Range(1, 100); // 1, 2, ..., 100 // query syntax:
var query = from n in numbers where n % 2 == 0 select n * 2; // method syntax:
var method = numbers .Where(n => n % 2 == 0) .Select(n => n * 2);

Vậy khi nào thì LinQ query tốt hơn LinQ method nhỉ? Mình nên xài cái nào đây?

Mình không biết các developer khác như thế nào, chứ riêng cá nhân mình, mình có cảm tình với LinQ method hơn, biết nói sao nhỉ, kiểu như thích thì thích thôi vậy đó. Có thể một phần khi tiếp xúc với JS, dùng callback nhiều nên dễ hiểu LinQ method hơn chăng.

Thật ra không có cái nào mạnh hơn cái nào đâu. Các bạn có thể dùng tool để chuyển từ LinQ query sang LinQ method đấy và ngược lại. Nên nếu bạn mong muốn cái nào có performance tốt hơn cái nào thì chúng như nhau cả thôi. Tuy nhiên, tùy vào trường hợp mà sử dụng, LinQ method trong vài trường hợp sẽ bộc lộ điểm yếu và đây là lúc LinQ query được dịp thể hiện. Cho nên ý mình ở đây tốt hơn nghĩa là đọc dễ hiểu hơn, dễ bảo trì hơn.

Nên bây giờ mình sẽ giải thích vì sao mình nói thế và show ra các điểm mạnh của LinQ query, sau cùng đi đến kết luận để phần nào các bạn tham khảo nhé.

Sử dụng từ khóa let

LinQ query có một thứ ghi điểm ở phần so sánh này, đó chính là sử dụng được từ khóa let. Nó cho phép bạn tạm thời chứa kết quả vào một biến và sử dụng nó ở nhiều chỗ khác nhau.

var querySyntax = from person in persons let yearsWorking = GetYearsWorking(person) where yearsWorking > 4 orderby yearsWorking select person.Name; var methodSyntax = persons .Select(person => new { YearsWorking = GetYearsWorking(person), Name = person.Name }) .Where(x => x.YearsWorking > 4) .OrderBy(x => x.YearsWorking) .Select(x => x.Name);

Như bạn thấy dùng let làm cho code của linq query nhìn dễ đọc hơn. Đối với linq method thì để làm được điều này ta phải tạo một anonymous class để chứa kết quả. Nhìn chung khi nào bạn cần một code dễ đọc, gọi một query con hay một hàm nhiều lần, cần lưu lại kết quả để sử dụng thì xài linq query với từ khóa let.

Query từ nhiều "nguồn" trong linq với from

Nếu bạn cần lấy data từ nhiều nguồn khác nhau thì làm thế nào, nguồn ở đây hiểu là dữ liệu từ một table, object, array hay collection. Hãy nhìn qua cách sử dụng trong linq query.

var rows = Enumerable.Range(1, 3); // 1, 2, 3
var columns = new string[] { "A", "B", "C"}; var querySyntax = from row in rows from col in columns select $"cell [{row}, {col}]"; var methodSyntax = rows.SelectMany(row => columns, (r, c) => $"cell [{r}, {c}]"); foreach (var cell in methodSyntax)
{ Console.WriteLine(cell);
}
// output:
// cell[1, A]
// cell[1, B]
// cell[1, C]
// cell[2, A]
// cell[2, B]
// cell[2, C]
// cell[3, A]
// cell[3, B]
// cell[3, C]

Mục đích với đoạn code trên là lấy data đồng thời từ hay nguồn dữ liệu là rowscolumns. Với từ khóa from thì bạn thấy đấy, code linq query nhìn rất dễ hiểu so với linq method phải không nào. Mình dám chắc linq method bạn hơi tốn chút nơ-ron thần kinh để đọc hiểu đấy 😛.

OrderBy hay orderby khi cần order data theo nhiều điều kiện

Với hai cú pháp đều có thể order dữ liệu theo nhiều điều kiện với nhau được. Bây giờ cũng xem qua ví dụ sau. Mình cần sắp xếp nhân viên trong công ty theo tuổi (age) sau đó là theo thu nhập(income). Có nghĩa là sắp xếp theo age xong xuôi rồi sẽ sắp xếp theo income.

var people = new Person[]
{ new Person() { Age = 20, Income = 5000, Name = "Viktor" }, new Person() { Age = 30, Income = 8000, Name = "Merry" }, new Person() { Age = 30, Income = 7000, Name = "Happy" }, new Person() { Age = 20, Income = 4000, Name = "Tony Stark" }, new Person() { Age = 20, Income = 6000, Name = "Madarin" }, new Person() { Age = 30, Income = 5500, Name = "Pepper" },
}; var querySyntax = from person in people orderby person.Age, person.Income select $"{person.Age} {person.Income} {person.Name}"; var methodSyntax = people .OrderBy(person => person.Age) .ThenBy(person => person.Income) .Select(person => $"{person.Age} {person.Income} {person.Name}"); // result
// 20 4000 Tony Stark
// 20 5000 Viktor
// 20 6000 Madarin
// 30 5500 Pepper
// 30 7000 Happy
// 30 8000 Merry

Chỗ này thì tùy vào cá nhân mỗi người thấy thích cách viết nào hơn thôi. Cả hai cú pháp đều làm rất tốt chỗ này. Tuy nhiên với linq query, orderby trên cùng một line code nhìn có vẻ gọn gàng xúc tích hơn.

Tiếp theo sẽ đến phần mà mình nghĩ tạo nên khác biệt khá lớn giữa hai cu cậu này, và chính điểm này làm mình thích linq query hơn.

Sử dụng GroupBy hay group hay hơn?

Cả hay đều giống nhau về mặt tính năng, đều dùng để group dữ liệu. group thì dùng trong linq query còn GroupBy là một extention method trong linq method. Vậy chính cách viết hay cách dùng sẽ nói lên sự khác biệt lớn nhất của hai thằng này, nào cùng xem qua ví dụ.

Chúng ta cần group tên của nhân vật theo chữ cái đầu tiên trong các tên đó.

var names = new string[] { "Alex", "George", "Alfredo", "Bo", "Greg", "Maxim" }; var querySyntax = from name in names group name by name[0]; var methodSyntax = names .GroupBy(name => name[0]); foreach (var pair in querySyntax)
{ var groupedName = string.Join(", ", pair.ToList()); Console.WriteLine($"Key = {pair.Key} Names = {groupedName}");
} // output:
// Key = A Names = Alex, Alfredo
// Key = G Names = George, Greg
// Key = B Names = Bo
// Key = M Names = Maxim foreach (var pair in methodSyntax)
{ var groupedName = string.Join(", ", pair.ToList()); Console.WriteLine($"Key = {pair.Key} Names = {groupedName}");
} // output:
// Key = A Names = Alex, Alfredo
// Key = G Names = George, Greg
// Key = B Names = Bo
// Key = M Names = Maxim

Thoạt nhìn thì không có vấn đề gì cho lắm nhưng GroupBy của linq method không chỉ có thế, nó còn support nhiều cái hơn nữa, ở phạm vi đơn giản nếu sử dụng nó thì sẽ hơi có chút khó hiểu khi đọc code mà thôi.

Để group nhiều điều kiện thì cũng tương tự:

var people = new Person[]
{ new Person() { Age = 20, Income = 4000, Name = "Viktor" }, new Person() { Age = 30, Income = 8000, Name = "Merry" }, new Person() { Age = 30, Income = 7000, Name = "Happy" }, new Person() { Age = 20, Income = 4000, Name = "Tony Stark" }, new Person() { Age = 30, Income = 6000, Name = "Madarin" }, new Person() { Age = 30, Income = 5500, Name = "Pepper" },
}; var querySyntax = from person in people group person by new { person.Age, person.Income } into grouped orderby grouped.Key.Age, grouped.Key.Income select grouped; var methodSyntax = people .GroupBy(person => new { person.Age, person.Income }) .OrderBy(person => person.Key.Age) .ThenBy(person => person.Key.Income); foreach (var person in querySyntax)
{ // Có thể select Name trong select linq query, vì select bắt buộc phải có khi viết theo cú pháp này // object trả về là grouped object này ở dạng { Key, person } var named = string.Join(", ", person.Select(x => x.Name).ToList()); Console.WriteLine($"Key = {person.Key} Names = {named}");
} foreach (var person in methodSyntax)
{ // Nếu không có select trong query thì phải select khi dùng // object trả về sẽ ở dạng { Key, person } var named = string.Join(", ", person.Select(x => x.Name).ToList()); Console.WriteLine($"Key = {person.Key} Names = {named}");
} // output
// Key = { Age = 20, Income = 4000 } Names = Viktor, Tony Stark
// Key = { Age = 30, Income = 5500 } Names = Pepper
// Key = { Age = 30, Income = 6000 } Names = Madarin
// Key = { Age = 30, Income = 7000 } Names = Happy
// Key = { Age = 30, Income = 8000 } Names = Merry

Cũng hơn lằng nhằng nhưng với linq query khi group với nhiều giá trị bắt buộc phải có into vào giá trị nào đấy, bên cạnh đó phải có thêm select. Linq method thì có thể nhận nhiều arguments hơn, cho phép "tùy chỉnh" lại kết quả bằng cách truyền một delegate vào tham số thứ hai.

Ở khoản này có vẻ linq query sẽ giúp nhìn clear hơn so với linq method, cơ mà việc đặt tên biến chỗ into cũng hơi hại não 😄.

Phép join thì sao

Đây là mấu chốt giúp linq query được nhiều developer chọn hơn so với linq method, cú pháp như sql lun OMG.

var categories = new Category[]
{ new Category() { Name = "Toys", Id = 1 }, new Category() { Name = "Electrical", Id = 2 },
};
var products = new Product[]
{ new Product() { Name = "Toy car", CategoryId = 1 }, new Product() { Name = "Blender", CategoryId = 2 }, new Product() { Name = "Washing machine", CategoryId = 2 }, new Product() { Name = "Bear", CategoryId = 1 },
}; var querySyntax = from product in products join category in categories on product.CategoryId equals category.Id select new { ProductName = product.Name, Category = category.Name }; var methodSyntax = products.Join(categories, product => product.CategoryId, category => category.Id, (product, category) => new { ProductName = product.Name, Category = category.Name }); foreach (var item in methodSyntax)
{ Console.WriteLine($"ProductName = {item.ProductName}, Category = {item.Category}");
} // result:
// ProductName = Toy car, Category = Toys
// ProductName = Blender, Category = Electrical
// ProductName = Washing machine, Category = Electrical
// ProductName = Bear, Category = Toys

Như các bạn đã thấy, khi join linq method cần tới mấy cái parameter để truyền vào, đầu tiên là bảng cần join, key cần map, và delegate trả về kết quả. Còn với linq query thì sao, mà thôi khỏi nói nữa, quá giống với sql rồi còn gì. Cho nên chỗ này mình sẽ bảo linq query là tốt nhất 😃) tốt về khía cạnh code dễ đọc và dễ viết.

Tóm lại

Với những cái đơn giản hay cần filter nhanh gọn lẹ dùng tới Where, Select, SelectMany, OrderBy ... thì mình thấy linq method ngon lành cành đào. Nếu hiểu biểu thức lamda bên C# hay rành rọt arrow function bên JS thì nhìn vào phát là hiểu ngay. Nói chung bài viết này không có nói ai tốt hơn ai, hay khuyên bảo bỏ cái này theo cái kia. Mục đích cung cấp bạn vài lợi thế của cú pháp kiểu query để bạn có cái nhìn rõ ràng. Có nhiều lập trình viên yêu thích cú pháp linq method lắm nhé, với code linq method công nhận cái đầu bá thiệt.

Một vài case gợi ý nên sử dụng linq query:

  • Dùng phép join
  • Query từ nhiều source
  • Cần query con ròi lưu lại vào biến để query cái khác sau (dùng từ khóa let)

Bình luận

Bài viết tương tự

- vừa được xem lúc

Các loại tham chiếu Nullable trong C# (Phần 1)

1. Giới thiệu. C# 8.0 giới thiệu kiểu tham chiếu nullable và kiểu tham chiếu non-nullable cho phép bạn đưa ra các lựa chọn quan trọng về thuộc tính cho các biến kiểu tham chiếu:.

0 0 36

- vừa được xem lúc

Command pattern qua ví dụ !

Command pattern là gì . Command pattern khá phổ biến trong C #, đặc biệt khi chúng ta muốn trì hoãn hoặc xếp hàng đợi việc thực hiện một yêu cầu hoặc khi chúng ta muốn theo dõi các hoạt động. Hơn nữa, chúng ta có thể hoàn tác tác chúng. .

0 0 178

- vừa được xem lúc

Hiểu Liskov Substitution Principle qua ví dụ !

Liskov Substitution Principle là gì . Nguyên tắc đóng mở xác đinh rằng các instance của lớp con có thể thay thế được instance lớp cha mà vẫn đảm bảo tính đúng đắn của chương trình.

0 0 24

- vừa được xem lúc

Creating custom Controls Wpf

Introduction. Wpf/winforms provides various controls like Buttons, Textbox, TextBlock, Labels etc.

0 0 41

- vừa được xem lúc

[P1] Chọn công nghệ nào để xây dựng website?

Hiện nay nhu cầu phát triển website, app tăng rất cao do xu hướng "số hóa 4.0" trong và ngoài nước.

0 0 71

- vừa được xem lúc

Kiểu dữ liệu trong C#

Dẫn nhập. Ở bài BIẾN TRONG C# chúng ta đã tìm hiểu về biến và có một thành phần không thể thiếu khi khai báo biến – Đó là kiểu dữ liệu.

0 0 24