LinQ c# là gì? Tìm hiểu về toán tử Join trong LINQ

Một mệnh đề được các lập trình viên sử dụng thường xuyên đó là Join. Join trong LinQ giúp nối các bảng dữ liệu một cách tối ưu, hiệu quả. Vậy thì join trong Linq là gì? Left outer join hay right outer join là như thế nào? Cùng Comdy tìm hiểu chi tiết qua bài viết này bạn nhé.

LinQ c# là gì?

LINQ là viết tắt của Language Integrated Query) trong C# là một phần của ngôn ngữ lập trình C# và .NET Framework, cung cấp một cách tiện lợi và linh hoạt để thực hiện các truy vấn trên dữ liệu từ các nguồn khác nhau như mảng, danh sách, cơ sở dữ liệu, XML, và nhiều nguồn dữ liệu khác.

LINQ cho phép lập trình viên sử dụng ngôn ngữ truy vấn được tích hợp trong C# để truy vấn và xử lý dữ liệu, thay vì phải sử dụng các phương thức và cú pháp truyền thống. Các truy vấn LINQ thường được viết bằng cách sử dụng các toán tử truy vấn như where, select, group by, orderby, và nhiều toán tử khác.

Toán tử Join trong LinQ

Toán tử Join trong LinQ
Các toán tử Join trong LinQ ghép nối hai danh sách và tạo ra một kết quả mới

Các toán tử Join ghép nối hai danh sách và tạo ra một kết quả mới. Bảng sau liệt kê các toán tử Join có sẵn trong LINQ:

Toán tử Mô tả
Join Toán tử Join ghép nối hai danh sách dựa trên một khóa và trả về danh sách kết quả. Nó giống như INNER JOIN của SQL.
GroupJoin Toán tử GroupJoin ghép nối hai danh sách dựa trên các khóa và trả về các nhóm danh sách. Nó giống như LEFT OUTER JOIN của SQL.

Toán tử Join hoạt động trên hai danh sách, danh sách bên trong và danh sách bên ngoài. Nó trả về một danh sách mới chứa các phần tử từ cả hai danh sách thỏa mãn biểu thức đã chỉ định. Nó giống như INNER JOIN của SQL.

Phương thức Join trong LinQ

Phương thức mở rộng Join có hai phương thức quá tải như dưới đây.

public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer, 
            IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, 
            Func<TInner, TKey> innerKeySelector, 
            Func<TOuter, TInner, TResult> resultSelector);

public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer, 
            IEnumerable<TInner> inner, 
            Func<TOuter, TKey> outerKeySelector,
            Func<TInner, TKey> innerKeySelector, 
            Func<TOuter, TInner, TResult> resultSelector,
            IEqualityComparer<TKey> comparer);

Ví dụ sau đây join hai danh sách kiểu chuỗi và trả về danh sách mới bao gồm các chuỗi tương ứng trong cả hai danh sách.

IList<string> strList1 = new List<string>() 
{ 
    "One", 
    "Two", 
    "Three", 
    "Four"
};

IList<string> strList2 = new List<string>() 
{ 
    "One", 
    "Two", 
    "Five", 
    "Six"
};

var innerJoin = strList1.Join(strList2,
    str1 => str1, 
    str2 => str2, 
    (str1, str2) => str1);
    
foreach (var str in innerJoinResult)
{			
    Console.WriteLine(str);
}

Đây là kết quả khi biên dịch và thực thi chương trình:

One 
Two

Bây giờ, hãy hiểu phương thức Join bằng cách sử dụng lớp Student và Standard trong đó lớp Student có thuộc tính StandardID tương ứng với thuộc tính StandardID của lớp Standard.

public class Student
{ 
    public int StudentID { get; set; }
    public string StudentName { get; set; }
    public int StandardID { get; set; }
}

public class Standard
{ 
    public int StandardID { get; set; }
    public string StandardName { get; set; }
}

Ví dụ sau đây min họa sử dụng phương thức Join trong cú pháp phương thức LINQ.

// Student collection
IList<Student> studentList = new List<Student>() 
{ 
    new Student() { StudentID = 1, StudentName = "John", Age = 18, StandardID = 1 } ,
    new Student() { StudentID = 2, StudentName = "Steve",  Age = 21, StandardID = 1 } ,
    new Student() { StudentID = 3, StudentName = "Bill",  Age = 18, StandardID = 2 } ,
    new Student() { StudentID = 4, StudentName = "Ram" , Age = 20, StandardID = 2 } ,
    new Student() { StudentID = 5, StudentName = "Ron" , Age = 21 } 
};

IList<Standard> standardList = new List<Standard>() 
{ 
    new Standard(){ StandardID = 1, StandardName="Standard 1"},
    new Standard(){ StandardID = 2, StandardName="Standard 2"},
    new Standard(){ StandardID = 3, StandardName="Standard 3"}
};

var innerJoinResult = studentList.Join(// outer sequence 
    standardList,  // inner sequence 
    student => student.StandardID,    // outerKeySelector
    standard => standard.StandardID,  // innerKeySelector
    (student, standard) => new  // result selector
        {
            StudentName = student.StudentName,
            StandardName = standard.StandardName
        });

foreach (var obj in innerJoinResult)
{    
    Console.WriteLine("{0} - {1}", obj.StudentName, obj.StandardName);
}

Đây là kết quả khi biên dịch và thực thi chương trình:

John - Standard 1
Steve - Standard 1
Bill - Standard 2
Ram - Standard 2

Trong ví dụ trên về truy vấn nối, studentList là danh sách bên ngoài vì truy vấn bắt đầu từ nó. Tham số đầu tiên trong phương thức Join được sử dụng để xác định danh sách bên trong là StandardList trong ví dụ trên.

Tham số thứ hai và thứ ba của phương thức Join được sử dụng để chỉ định trường có giá trị khớp với biểu thức lambda để đưa phần tử vào kết quả.

Biểu thức student => student.StandardID lấy trường StandardID của từng phần tử trong studentList làm khóa.

Biểu thức standard => standard.StandardID lấy trường StandardID của từng phần tử trong standardList làm khóa

Nếu giá trị của cả hai khóa này khớp với nhau thì phần tử đó được đưa vào danh sách kết quả.

Tham số cuối cùng trong phương thức Join là một biểu thức để tạo kết quả. Trong ví dụ trên, kết quả trả về là một kiểu ẩn danh bao gồm thuộc tính StudentName và StandardName của cả hai danh sách.

Khóa StandardID của cả hai danh sách phải khớp thì mới được đưa vào kết quả, ngược lại thì sẽ không được đưa vào kết quả. Ví dụ: sinh viên Ron không được liên kết với bất kỳ Standard nào nên sinh viên Ron không được thêm vào kết quả.

Mệnh đề join trong cú pháp truy vấn LinQ

Mệnh đề join trong cú pháp truy vấn LinQ
Mệnh đề join trong cú pháp truy vấn LinQ đòi hỏi danh sách bên ngoài, danh sách bên trong, bộ chọn khóa và bộ chọn kết quả.

Toán tử join linq trong cú pháp truy vấn hoạt động hơi khác so với cú pháp phương thức. Nó đòi hỏi danh sách bên ngoài, danh sách bên trong, bộ chọn khóa và bộ chọn kết quả.

Từ khóa on được sử dụng cho bộ chọn khóa trong đó phía bên trái của toán tử equals là khóa của danh sách bên ngoài (outerKey) và bên phải của nó là khóa của danh sách bên trong (innerKey).

Dưới đây là cú pháp của mệnh đề linq join trong cú pháp truy vấn LINQ.

from ... in outerSequence

join ... in innerSequence on outerKey equals innerKey

select ...

Ví dụ sau đây về toán tử join trong cú pháp truy vấn trả về một tập hợp các phần tử từ studentList và standardList nếu hai thuộc tính Student.StandardID và Standard.StandardID của chúng khớp nhau.

// Student collection
IList<Student> studentList = new List<Student>() 
{ 
    new Student() { StudentID = 1, StudentName = "John", Age = 18, StandardID = 1 } ,
    new Student() { StudentID = 2, StudentName = "Steve",  Age = 21, StandardID = 1 } ,
    new Student() { StudentID = 3, StudentName = "Bill",  Age = 18, StandardID = 2 } ,
    new Student() { StudentID = 4, StudentName = "Ram" , Age = 20, StandardID = 2 } ,
    new Student() { StudentID = 5, StudentName = "Ron" , Age = 21 } 
};

IList<Standard> standardList = new List<Standard>() 
{ 
    new Standard(){ StandardID = 1, StandardName="Standard 1"},
    new Standard(){ StandardID = 2, StandardName="Standard 2"},
    new Standard(){ StandardID = 3, StandardName="Standard 3"}
};

var innerJoinResult = from s in studentList // outer sequence
                      join st in standardList //inner sequence 
                          on s.StandardID equals st.StandardID // key selector 
                      select new 
					  { // result selector 
                          StudentName = s.StudentName, 
                          StandardName = st.StandardName 
                      };

foreach (var obj in innerJoinResult)
{    
    Console.WriteLine("{0} - {1}", obj.StudentName, obj.StandardName);
}

Đây là kết quả khi biên dịch và thực thi chương trình:

John - Standard 1
Steve - Standard 1
Bill - Standard 2
Ram - Standard 2

Lưu ý: Sử dụng toán tử equals để khớp với bộ linq c# là gì

chọn khóa trong cú pháp truy vấn. Toán tử == không hợp lệ.

Toán tử GroupJoin LinQ

Toán tử GroupJoin LinQ
Toán tử GroupJoin ghép nối hai danh sách dựa trên khóa bằng cách khớp khóa của hai danh sách

Cú pháp của phương thức GroupJoin

Toán tử GroupJoin ghép nối hai danh sách dựa trên khóa bằng cách khớp khóa của hai danh sách và trả về tập hợp kết quả là một danh sách gồm khóa và danh sách được nhóm.

GroupJoin giống như LEFT OUTER JOIN của SQL.

GroupJoin yêu cầu các tham số tương tự như Join. GroupJoin có hai phương thức quá tải sau:

public static IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer, 
    IEnumerable<TInner> inner, 
    Func<TOuter, TKey> outerKeySelector, 
    Func<TInner, TKey> innerKeySelector, 
    Func<TOuter, IEnumerable<TInner>, TResult> resultSelector);

public static IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer, 
    IEnumerable<TInner> inner, 
    Func<TOuter, TKey> outerKeySelector, 
    Func<TInner, TKey> innerKeySelector, 
    Func<TOuter, IEnumerable<TInner>, TResult> resultSelector, 
    IEqualityComparer<TKey> comparer);

Ví dụ dưới đây minh họa phương thức mở rộng GroupJoin sử dụng cú pháp phương thức LINQ:

// Student collection
IList<Student> studentList = new List<Student>() 
{ 
    new Student() { StudentID = 1, StudentName = "John", Age = 18, StandardID = 1 },
    new Student() { StudentID = 2, StudentName = "Steve",  Age = 21, StandardID = 1 },
    new Student() { StudentID = 3, StudentName = "Bill",  Age = 18, StandardID = 2 },
    new Student() { StudentID = 4, StudentName = "Ram", Age = 20, StandardID = 2 },
    new Student() { StudentID = 5, StudentName = "Ron", Age = 21 } 
};

IList<Standard> standardList = new List<Standard>() 
{ 
    new Standard(){ StandardID = 1, StandardName="Standard 1"},
    new Standard(){ StandardID = 2, StandardName="Standard 2"},
    new Standard(){ StandardID = 3, StandardName="Standard 3"}
};

var groupJoin = standardList.GroupJoin(studentList,  //inner sequence
    std => std.StandardID, //outerKeySelector 
    s => s.StandardID,     //innerKeySelector
    (std, studentsGroup) => new // resultSelector 
    {
        Students = studentsGroup,
        StandarFulldName = std.StandardName
    });

foreach (var item in groupJoin)
{ 
    Console.WriteLine("{0}:", item.StandarFulldName);

    foreach(var stud in item.Students)
    {
        Console.WriteLine("- {0}", stud.StudentName);
    }
}

Đây là kết quả khi biên dịch và thực thi chương trình:

Standard 1:
- John
- Steve
Standard 2:
- Bill
- Ram
Standard 3:

Trong ví dụ trên của truy vấn GroupJoin, standardList là danh sách bên ngoài, vì truy vấn bắt đầu từ nó. Tham số đầu tiên trong phương thức GroupJoin chỉ định danh sách bên trong – chính là studentList.

Tham số thứ hai và thứ ba của phương thức GroupJoin được sử dụng để chỉ định trường có giá trị khớp với biểu thức lambda để đưa phần tử vào kết quả.

Biểu thức student => student.StandardID lấy trường StandardID của từng phần tử trong studentList làm khóa.

Biểu thức standard => standard.StandardID lấy trường StandardID của từng phần tử trong standardList làm khóa

Nếu giá trị của cả hai khóa này khớp với nhau thì phần tử đó được đưa vào nhóm danh sách kết quả.

Tham số cuối cùng trong phương thức GroupJoin là một biểu thức để tạo kết quả. Trong ví dụ trên, kết quả trả về là một kiểu ẩn danh bao gồm thuộc tính StandardName và Students (danh sách sinh viên theo StandardID).

Hình ảnh sau đây minh họa rằng danh sách bên trong được đưa vào danh sách studentsGroup để khớp với khóa StandardID và nó có thể được sử dụng để tạo kết quả.

Tập kết quả sẽ bao gồm một đối tượng ẩn danh có các thuộc tính Students và StandardFullName. Thuộc tính Students là một danh sách các Student có StandardID khớp với Standard.StandardID.

Mệnh đề GroupJoin trong Cú pháp truy vấn

Mệnh đề GroupJoin trong cú pháp truy vấn
Mệnh đề GroupJoin trong cú pháp truy vấn đòi hỏi một danh sách bên ngoài, danh sách bên trong, bộ chọn khóa và bộ chọn kết quả.

Toán tử GroupJoin trong cú pháp truy vấn hoạt động hơi khác so với cú pháp phương thức. Nó đòi hỏi một danh sách bên ngoài, danh sách bên trong, bộ chọn khóa và bộ chọn kết quả.

Từ khóa on được sử dụng cho bộ chọn khóa trong đó phía bên trái của toán tử equals là khóa của danh sách bên ngoài (outerKey) và bên phải của nó là khóa của danh sách bên trong (innerKey).

Dưới đây là cú pháp của mệnh đề GroupJoin trong cú pháp truy vấn LINQ.

from ... in outerSequence

join ... in innerSequence on outerKey equals innerKey

into groupedCollection    

select ...

Ví dụ sau đây cho thấy GroupJoin trong cú pháp truy vấn.

// Student collection
IList<Student> studentList = new List<Student>() 
{ 
    new Student() { StudentID = 1, StudentName = "John", Age = 18, StandardID = 1 },
    new Student() { StudentID = 2, StudentName = "Steve",  Age = 21, StandardID = 1 },
    new Student() { StudentID = 3, StudentName = "Bill",  Age = 18, StandardID = 2 },
    new Student() { StudentID = 4, StudentName = "Ram", Age = 20, StandardID = 2 },
    new Student() { StudentID = 5, StudentName = "Ron", Age = 21 } 
};

IList<Standard> standardList = new List<Standard>() 
{ 
    new Standard(){ StandardID = 1, StandardName="Standard 1"},
    new Standard(){ StandardID = 2, StandardName="Standard 2"},
    new Standard(){ StandardID = 3, StandardName="Standard 3"}
};

var groupJoin = from std in standardList 
                join s in studentList on std.StandardID equals s.StandardID
                into studentGroup
                select new 
                { 
                    Students = studentGroup, 
                    StandardName = std.StandardName 
                };

foreach (var item in groupJoin)
{ 
    Console.WriteLine(item.StandarFulldName );

    foreach(var stud in item.Students)
    {
        Console.WriteLine(stud.StudentName);
    }
}

Đây là kết quả khi biên dịch và thực thi chương trình:

Standard 1:
- John
- Steve
Standard 2:
- Bill
- Ram
Standard 3:

Lưu ý: Sử dụng toán tử equals để khớp với bộ chọn khóa. Toán tử == không hợp lệ.

Những điểm cần nhớ về toán tử Join trong LINQ

  • C# linq join và GroupJoin là các toán tử ghép nối.
  • Join giống như INNER JOIN của SQL. Nó trả về một danh sách mới chứa các phần tử khớp khóa từ hai danh sách.
  • Toán tử Join ghép nối danh sách bên trong và danh sách bên ngoài và tạo ra một danh sách kết quả.
  • GroupJoin giống như LEFT OUTER JOIN của SQL. Nó trả về một danh sách mới chứa khóa và danh sách được nhóm theo khóa.

LinQ right join và LinQ left join

LinQ right join và LinQ left join
Tìm hiểu chi tiết về sự khác nhau giữa linQ right join và LinQ left join

Left join (Outer join)

LEFT JOIN (left outer join in linq) trả về tất cả các bản ghi từ bảng bên trái và các bản ghi khớp từ bảng bên phải. Nếu không có khớp, các giá trị của bảng bên phải sẽ là null.

Right join (Outer join)

RIGHT JOIN trả về tất cả các bản ghi từ bảng bên phải và các bản ghi khớp từ bảng bên trái. Nếu không có khớp, các giá trị của bảng bên trái sẽ là null.

C# iequalitycomparer là gì?

C# iequalitycomparer là gì
C# iequalitycomparer được sử dụng khi bạn muốn thực hiện so sánh tùy chỉnh cho các loại dữ liệu không hỗ trợ so sánh mặc định

Trong C#, IEqualityComparer<T> là một interface được sử dụng để định nghĩa cách so sánh đối tượng của kiểu T để xác định xem chúng có bằng nhau hay không.

Interface này chủ yếu được sử dụng khi bạn muốn thực hiện so sánh tùy chỉnh cho các loại dữ liệu không hỗ trợ so sánh mặc định hoặc khi bạn muốn thay đổi quy tắc so sánh mặc định.

IEqualityComparer<T> có hai phương thức chính:

  • Equals(T x, T y): Phương thức này kiểm tra xem hai đối tượng x và y có bằng nhau hay không.
  • GetHashCode(T obj): Phương thức này trả về mã băm của đối tượng đã cho, được sử dụng trong quá trình so sánh.

C# linq inner join là gì?

INNER JOIN là một loại join sử dụng để kết hợp các hàng từ hai nguồn dữ liệu (ví dụ: hai bảng) dựa trên một điều kiện khớp giữa chúng. INNER JOIN trả về các bản ghi mà có giá trị trong cả hai bảng.

Iqueryable và ienumerable

Iqueryable và ienumerable
IEnumerable và IQueryable là hai giao diện trong .NET Framework

IEnumerableIQueryable là hai giao diện trong .NET Framework được sử dụng để thực hiện các truy vấn trên các tập hợp dữ liệu, nhưng chúng có một số khác biệt quan trọng trong cách chúng xử lý và truy xuất dữ liệu.

Iqueryable

  • Nằm trong namespace: System.Collections.
  • Interface này chứa một phương thức là GetEnumerator, được sử dụng để lặp qua các phần tử trong tập hợp.
  • Phù hợp cho việc thực hiện truy vấn trên các tập hợp dữ liệu tĩnh (in-memory data).
  • Thực hiện truy vấn LINQ trên các cấu trúc dữ liệu như mảng, danh sách, tập hợp, v.v.
  • Tích hợp với LINQ to Objects.

Ienumerable

  • Nằm trong namespace: System.Linq.
  • Interface này mở rộng từ IEnumerable.
  • Chứa các phương thức chuyên biệt để thực hiện truy vấn từ xa, thường được sử dụng với các nguồn dữ liệu như cơ sở dữ liệu.
  • Phù hợp cho việc thực hiện truy vấn trên các nguồn dữ liệu lớn, chẳng hạn như cơ sở dữ liệu.
  • Hỗ trợ thực hiện truy vấn LINQ to SQL, LINQ to Entities, và các nguồn dữ liệu IQueryable khác

Entity framework inner join là gì?

Entity Framework là một Object-Relational Mapping trong .NET Framework. Nó cung cấp một cách thuận tiện để làm việc với cơ sở dữ liệu từ mã nguồn .NET bằng cách ánh xạ các đối tượng của ứng dụng vào bảng trong cơ sở dữ liệu. Khi bạn làm việc với Entity Framework và muốn kết hợp các bảng trong cơ sở dữ liệu, bạn thường sử dụng LINQ để thực hiện các truy vấn, bao gồm INNER JOIN.

Kết lại

Trên đây là toàn bộ chia sẻ của Comdy về phép join trong LinQ. Hi vọng những kiến thức hữu ích trong bài viết này là ý nghĩa đối với bạn. Xin cám ơn vì đã theo dõi và ủng hộ.

 

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *