Linq C# Là Gì

  -  

*

LINQ cho phép ta tiến hành query để đọc dữ liệu trải qua interface IQueryable. Chúng ta truyền vào trong 1 Expression Tree, rồi provider sẽ gửi Expression Tree kia thành query tương xứng với data source. Thông thường, ta dùng lambda expression để tạo ra Expression Tree. Nhưng lại khi nên thiết, ta cũng hoàn toàn có thể tự mình tạo Expression Tree.

Bạn đang xem: Linq c# là gì

Các chúng ta có thể download code ví dụ như từ đường links dưới đây.

https://github.com/tanhailonghotel.com.vnbk/ExpressionTreeDemo

Dữ liệu để test

Các lớp DTO

Trong code production, data source của ta đang là database. Tuy nhiên trong bài bác này ta đọc tài liệu từ memory. Dưới đấy là các lớp DTO.

public class Person public string Name get; set; public int Age get; set; public DateTime Dob get; set; public override string ToString() return $"Name: Name, Age: Age, Dob: Dob"; public class Document public string Title get; set; public DateTime IssuedBy get; set; public override string ToString() return $"Title: Title, IssuedBy: IssuedBy"; public class Recipe public string Name get; set; public IList Ingredients get; set; = new List(); public override string ToString() return $"Name: string.Join(", ", Ingredients) ";

Dữ liệu test

Ta tạo một số dữ liệu như dưới đây.

Tạo query với lambda expression

Khác biệt giữa LINQ cho IEnumerable và mang lại IQueryable

Thoạt quan sát qua, LINQ predicate để đọc tài liệu từ IEnumerable với từ IQueryable trông giống hệt nhau. Dẫu vậy chúng có một điểm khác biệt căn bản.

Với IEnumerable, ta cần sử dụng delegate làm cho predicate.Với IQueryable, ta dùng Expression Tree làm cho predicate.

Nếu ta áp dụng delegate cùng với IQueryable thì runtime sẽ đưa nó thành Expression Tree.

Và ta cũng hoàn toàn có thể chuyển IEnumerable thành IQueryable.

var peopleList = >;var people = peopleList.AsQueryable();var documentsList = >;var documents = documentsList.AsQueryable();

Tạo Expression Tree với lambda expression

Dưới đấy là cách dùng lambda expression nhằm đọc toàn bộ tên và tiêu đề trường đoản cú collection.

var filteredPeople = people.Where(p.Dob > new DateTime(1980, 12, 31));var filteredDocuments = documents.Where(p.IssuedBy > new DateTime(2000, 1, 1));Có thể thấy rằng ta phải hard-code thương hiệu của attribute vào lambda expression. Vấn đề tạo một hàm chung cho cả 2 collection sinh hoạt trên là kha khá khó. Dưới đấy là một số trường hợp mà lại hàm chung là có ích.

Một hàm chung nhận vào tên attribute làm cho tham số, rồi lấy tất cả giá trị của attribute đó.Một hàm tầm thường để lọc dữ liệu dựa trên thời gian khởi chế tạo ra (Dob hoặc IssuedBy) nhưng mà không nên hard-code thương hiệu attribute..etc

Tự tạo Expression Tree

Predicate mang lại IQueryable tất cả dạng Expression>. Ta rất có thể chia LINQ predicate làm cho 2 loại chính.

Expression>: được dùng trong số hàm gọi dữ liệu. Ví dụ: Select/SelectMany/Max/....Expression>: được dùng trong các hàm thanh lọc dữ liệu. Ví dụ: First/Where/Single/....

Expression Tree để đọc dữ liệu

Ta sẽ ban đầu từ trường hợp đơn giản nhất: đọc tài liệu của một attribute vào collection. Code của ta sẽ khớp ứng với lambda expression bên dưới đây, nhưng lại ta không bắt buộc hard-code thương hiệu attribute.

var values = collection.Select(c => c.);// với collection people: var names = people.Select(p => p.Name);Các bạn cũng có thể tham khảo code hoàn hảo tại đây.

private static IQueryable GetField(IQueryable collection, string columnName) var collectionTypeExpr = Expression.Parameter(typeof(TSource)); // ParameterExpression var columnPropertyExpr = Expression.Property(collectionTypeExpr, columnName); // MemberExpression var predicate = Expression.Lambda>(columnPropertyExpr, collectionTypeExpr); return collection.Select(predicate);Collection của ta cần có dạng IQueryable. Còn thương hiệu attribute được truyền bên dưới dạng string. Để ý là kiểu dữ liệu trả về cũng chính là generic. Tiếp đến ta tạo thành 2 expression tương ứng với collection và với attribute nhưng mà ta ao ước đọc. Cuối cùng, ta cần sử dụng hàm Expression.Lambda để chế tạo ra Expression Tree. Lúc này, predicate vừa tạo có thể được dùng để đọc quý giá của attribute từ bỏ collection.

Như đang nói tại đoạn trước, predicate của ta có kiểu là Expression>.

Dưới phía trên là tác dụng test.

Xem thêm: Tocopheryl Acetate Là Gì - Lợi Ích Với Ngành Làm Đẹp Và Sức Khỏe

var names = GetField(_people, nameof(Person.Name));// John Doe// Jane Doe// Baby Doe

Expression Tree nhằm lọc dữ liệu

Trong lấy ví dụ tiếp theo, ta chế tác một hàm bình thường để thanh lọc dữ liệu dựa vào ngày khởi tạo. Cùng với Person, ta thực hiện Dob. Còn cùng với Document, ta cần sử dụng IssuedBy. Hàm của ta sẽ khớp ứng với code dưới đây.

var values = collection.Where(c => c. > lowerBound && c. p.Dob > lowerBound && p.IssuedBy Các bạn có thể tham khảo code hoàn chỉnh tại đây. Dưới đấy là một số loại đáng chú ý.

var olderThanExpr = Expression.GreaterThan(timePropertyExpr, Expression.Constant(lower));BinaryExpression này chính là cận bên dưới của thời gian khởi tạo. Chính vì vậy ta sử dụng hàm GreaterThan.

var newerThanExpr = Expression.LessThan(timePropertyExpr, Expression.Constant(upper));BinaryExpression này đó là cận bên trên của thời khắc khởi tạo. Vì vậy ta sử dụng hàm LessThan.

var timeRangeExpr = Expression.And(newerThanExpr, olderThanExpr);Sau khi tạo thành 2 expression trên, ta hoàn toàn có thể tạo được khoảng thời gian để thanh lọc dữ liệu. Khoảng thời gian này cũng là một BinaryExpression. Ta chỉ cần kết hợp cận trên với cận dưới vừa tạo.

var predicate = Expression.Lambda>(timeRangeExpr, parameterExpr);Như đã nói tại đoạn trước, predicate của ta bao gồm kiểu là Expression>.

Dưới trên đây là tác dụng test.

var peopleStartsWithJo = people.Where(p => p.Name.StartsWith("Jo"));Đây là code trả chỉnh. Ta đang xem từng dòng.

var methodInfo = typeof(string).GetMethods() .Single(m => m.Name == nameof(string.StartsWith) && m.GetParameters().Length == 1 && m.GetParameters().Single().ParameterType == typeof(string));Để gọi hàm trong Expression Tree, ta bắt buộc lấy được method info của hàm đó. Vày hàm string.StartsWith có tương đối nhiều overload đề nghị ta bắt buộc tìm đúng hàm gồm một parameter với đẳng cấp string. Ta có thể cache quý giá method info này để nâng cấp hiệu năng của code.

var startsWithExpr = Expression.Call(columnProperty, methodInfo, Expression.Constant(prefix));Ta cần sử dụng hàm Expression.Call để chế tạo ra một MethodCallExpression. Hàm gọi cũng có nhiều overload, nhưng ta sử dụng overload để điện thoại tư vấn hàm instance.

Kết quả thu được là đúng thật ta ý muốn muốn.

var recipesWithEggs = recipes.Where(r => r.Ingredients.Contains("eggs"));Xin xem thêm code hoàn chỉnh tại đây. Ta đã biết phương pháp gọi hàm trong Expression Tree. Và dưới đây là một số khác hoàn toàn khi hotline hàm generic static thay vì hàm instance.

var methodInfo = typeof(Enumerable).GetMethods() .Single(m => m.Name == nameof(Enumerable.Contains) && m.GetParameters().Length == 2);var containsMethod = methodInfo.MakeGenericMethod(typeof(TField));Code nhằm tìm overload tương thích là gần tương tự phần trước, nhưng ta còn yêu cầu phải hỗ trợ kiểu dữ liệu cho hàm generic. Method info này cũng hoàn toàn có thể được cache khi cần.

var containsExpr = Expression.Call(containsMethod, columnProperty, Expression.Constant(value));Mặc dù ta vẫn sử dụng hàm Expression.Call, lần này ta sẽ dùng overload có cung cấp hàm static.

Code của ta rất có thể lọc được cách làm nấu ăn uống dựa theo nguyên liệu một cách thiết yếu xác.

var recipeWithEggs = GetWithFieldContainValue(_recipes, nameof(Recipe.Ingredients), "eggs");// Fried Rice: eggs, rice, oil, vegetables // Omelette: eggs, butter, oil

Kết thúc

Đôi khi trong những khi sử dụng LINQ, tôi bắt buộc viết những lambda expression với cùng súc tích mà chỉ không giống tên attribute. Thời gian đó tôi sẽ có được 2 lựa chọn.

Xem thêm: Isf Là Gì ? Tìm Hiểu Khái Niệm

Tạo một Expression Tree có thể xử lý được tất cả các data source cùng qua đó đào thải trùng lặp code.