Triển khai các phép nối dữ liệu Inner, Left và Right bằng LINQ trong C#

Trong quá trình phát triển ứng dụng .NET, việc tổng hợp dữ liệu từ nhiều collection khác nhau là một yêu cầu phổ biến. LINQ (Language Integrated Query) cung cấp các toán tử mạnh mẽ để thực hiện các phép nối tương tự như cấu trúc SQL ngay trên mã nguồn C#. Bài viết này sẽ hướng dẫn cách thực hiện Inner Join, Left Join và Right Join sử dụng cả cú pháp Query và biểu thức Lambda.

1. Thiết lập mô hình dữ liệu

Để minh họa, chúng ta xây dựng hai lớp đối tượng đại diện cho mối quan hệ giữa người dùng và thông tin liên lạc. Một người dùng có thể có nhiều số điện thoại hoặc địa chỉ liên hệ.

public class NguoiDung
{
    public int MaSo { get; set; }
    public string HoTen { get; set; }
    public string Email { get; set; }
}

public class ChiTietLienHe
{
    public int IdLienHe { get; set; }
    public int MaNguoiDung { get; set; }
    public string SoDienThoai { get; set; }
    public string DiaChi { get; set; }
}

Dưới đây là phương thức khởi tạo dữ liệu mẫu để kiểm tra các kịch bản nối:

public static List<NguoiDung> KhoiTaoDanhSachNguoiDung()
{
    return new List<NguoiDung>
    {
        new NguoiDung { MaSo = 1, HoTen = "Nguyen Van A", Email = "a@example.com" },
        new NguoiDung { MaSo = 2, HoTen = "Tran Thi B", Email = "b@example.com" },
        new NguoiDung { MaSo = 3, HoTen = "Le Van C", Email = "c@example.com" }
    };
}

public static List<ChiTietLienHe> KhoiTaoDanhSachLienHe()
{
    return new List<ChiTietLienHe>
    {
        new ChiTietLienHe { IdLienHe = 1, MaNguoiDung = 1, SoDienThoai = "0901111111", DiaChi = "Ha Noi" },
        new ChiTietLienHe { IdLienHe = 2, MaNguoiDung = 1, SoDienThoai = "0902222222", DiaChi = "Da Nang" },
        new ChiTietLienHe { IdLienHe = 3, MaNguoiDung = 5, SoDienThoai = "0903333333", DiaChi = "HCM" } 
        // MaNguoiDung = 5 không tồn tại trong danh sách người dùng
    };
}

2. Thực hiện Inner Join

Phép nối trong chỉ trả về các bản ghi có sự khớp nối giữa hai tập dữ liệu dựa trên khóa ngoại.

Sử dụng cú pháp Query

var ketQuaInner = from user in KhoiTaoDanhSachNguoiDung()
                  join contact in KhoiTaoDanhSachLienHe()
                  on user.MaSo equals contact.MaNguoiDung
                  select new
                  {
                      TenNguoiDung = user.HoTen,
                      SoDienThoai = contact.SoDienThoai
                  };

Sử dụng biểu thức Lambda

var ketQuaInnerLambda = KhoiTaoDanhSachNguoiDung()
    .Join(KhoiTaoDanhSachLienHe(),
          u => u.MaSo,
          c => c.MaNguoiDung,
          (u, c) => new { TenNguoiDung = u.HoTen, SoDienThoai = c.SoDienThoai });

3. Thực hiện Left Join

Left Join giữ lại tất cả các bản ghi từ tập dữ liệu bên trái. Nếu không tìm thấy bản ghi khớp ở bên phải, giá trị tương ứng sẽ là null.

Sử dụng cú pháp Query

Kỹ thuật này sử dụng từ khóa into để nhóm kết quả tạm thời, sau đó dùng DefaultIfEmpty() để xử lý các trường hợp không khớp.

var ketQuaLeft = from user in KhoiTaoDanhSachNguoiDung()
                 join contact in KhoiTaoDanhSachLienHe()
                 on user.MaSo equals contact.MaNguoiDung into NhomLienHe
                 from c in NhomLienHe.DefaultIfEmpty()
                 select new
                 {
                     TenNguoiDung = user.HoTen,
                     SoDienThoai = c != null ? c.SoDienThoai : "Khong co thong tin"
                 };

Sử dụng biểu thức Lambda

Trong cú pháp phương thức, chúng ta kết hợp GroupJoinSelectMany để đạt được hiệu quả tương tự.

var ketQuaLeftLambda = KhoiTaoDanhSachNguoiDung()
    .GroupJoin(KhoiTaoDanhSachLienHe(),
               u => u.MaSo,
               c => c.MaNguoiDung,
               (u, cGroup) => new { User = u, Contacts = cGroup })
    .SelectMany(
        x => x.Contacts.DefaultIfEmpty(),
        (x, c) => new { TenNguoiDung = x.User.HoTen, SoDienThoai = c != null ? c.SoDienThoai : "Khong co thong tin" }
    );

4. Thực hiện Right Join

LINQ không hỗ trợ trực tiếp toán tử Right Join. Để thực hiện, chúng ta đảo ngược vị trí của hai collection và áp dụng logic của Left Join.

Sử dụng cú pháp Query

var ketQuaRight = from contact in KhoiTaoDanhSachLienHe()
                  join user in KhoiTaoDanhSachNguoiDung()
                  on contact.MaNguoiDung equals user.MaSo into NhomUser
                  from u in NhomUser.DefaultIfEmpty()
                  select new
                  {
                      TenNguoiDung = u != null ? u.HoTen : "Khong xac dinh",
                      SoDienThoai = contact.SoDienThoai
                  };

Sử dụng biểu thức Lambda

var ketQuaRightLambda = KhoiTaoDanhSachLienHe()
    .GroupJoin(KhoiTaoDanhSachNguoiDung(),
               c => c.MaNguoiDung,
               u => u.MaSo,
               (c, uGroup) => new { Contact = c, Users = uGroup })
    .SelectMany(
        x => x.Users.DefaultIfEmpty(),
        (x, u) => new { TenNguoiDung = u != null ? u.HoTen : "Khong xac dinh", SoDienThoai = x.Contact.SoDienThoai }
    );

Thẻ: c-sharp linq lambda-expression dotnet JOIN-Operations

Đăng vào ngày 24 tháng 5 lúc 03:36