Bài 1: Giới thiệu về Trình quản lý quảng cáo

 

🎓 BÀI GIẢNG: HIỂN THỊ DANH SÁCH DỮ LIỆU BẰNG LINQ TRONG SERVICE (.NET 8, EF CORE)


💡 Mục tiêu

  • Biết cách tạo class Service cho từng bảng.

  • Biết tiêm Dependency (DI) để sử dụng DbContext.

  • Thực hành các kiểu truy vấn LINQ phổ biến:
    👉 OrderBy, Join, Where, Paging, Select ViewModel.


1️⃣ Tạo class Service và cấu hình Dependency Injection

🔹 Model

public partial class KhoaHoc
{  
    public int ID { get; set; }
    public string TenKhoaHoc { get; set; }
    public int? idChuDe { get; set; }
    public int? ThuTu { get; set; }
    public string HinhAnh { get; set; }
    public string MoTa { get; set; }
    public string BaiViet { get; set; }
    public string GiangVien { get; set; }
    public DateOnly? ThoiGianTao { get; set; }
    public bool? isCongKhai { get; set; }
    public virtual ChuDe idChuDeNavigation { get; set; }
    public virtual ICollection<DangKyKhoaHoc> DangKyKhoaHocs { get; set; } = new List<DangKyKhoaHoc>();
    public virtual ICollection<Video> Videos { get; set; } = new List<Video>();
}

🔹 DbContext

public class AppDbContext : DbContext
{
    public DbSet<KhoaHoc> KhoaHocs { get; set; }
    public DbSet<ChuDe> ChuDes { get; set; }
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
}

🔹 Service

public class KhoaHocService
{
    private readonly AppDbContext _db;
    public KhoaHocService(AppDbContext db)
    {
        _db = db;
    }
}

👉 Trong Program.cs:

builder.Services.AddScoped<KhoaHocService>();

👉 Trong KhoaHocController.cs:

public class KhoaHocController : Controller
{
    private readonly KhoaHocService _service;
    public KhoaHocController(KhoaHocService service)
    {
        _service = service;
    }
    public IActionResult DanhSach()
    {
        var list = _service.GetAll();
        return View(list);
    }
}

📋 2️⃣ Hàm get danh sách cơ bản (OrderBy, Count, Sum)

public List<KhoaHoc> GetAll()
{
    return _db.KhoaHocs
              .OrderByDescending(x => x.ThoiGianTao)
              .ToList();
}

public int TongKhoaHoc()
{
    return _db.KhoaHocs.Count();
}

public int SoLuongCongKhai()
{
    return _db.KhoaHocs.Count(x => x.isCongKhai == true);
}

🔗 3️⃣ Hàm get danh sách có INNER JOIN với bảng ChuDe

public List<dynamic> GetJoinChuDe()
{
    var query = from kh in _db.KhoaHocs
                join cd in _db.ChuDes on kh.idChuDe equals cd.ID
                orderby kh.ThoiGianTao descending
                select new
                {
                    kh.ID,
                    kh.TenKhoaHoc,
                    cd.TenChuDe,
                    kh.GiangVien,
                    kh.ThoiGianTao
                };
    return query.ToList<dynamic>();
}

🧠 Tương đương SQL:

SELECT kh.ID, kh.TenKhoaHoc, cd.TenChuDe, kh.GiangVien, kh.ThoiGianTao
FROM KhoaHocs kh
JOIN ChuDes cd ON kh.idChuDe = cd.ID
ORDER BY kh.ThoiGianTao DESC

🔍 4️⃣ Hàm get danh sách có truy vấn WHERE (lọc tham số)

public List<KhoaHoc> GetByFilter(string? keyword, bool? congKhai, int? idChuDe)
{
    var query = _db.KhoaHocs.AsQueryable();

    if (!string.IsNullOrEmpty(keyword))
        query = query.Where(x => x.TenKhoaHoc.Contains(keyword) || x.MoTa.Contains(keyword));

    if (congKhai.HasValue)
        query = query.Where(x => x.isCongKhai == congKhai.Value);

    if (idChuDe.HasValue)
        query = query.Where(x => x.idChuDe == idChuDe.Value);

    return query
        .OrderByDescending(x => x.ThoiGianTao)
        .ToList();
}

🔎 LINQ tự động tạo câu SQL WHERE tương ứng chỉ với tham số có giá trị.


📄 5️⃣ Hàm danh sách có phân trang (Paging)

public List<KhoaHoc> GetPaging(int page = 1, int pageSize = 10)
{
    var query = _db.KhoaHocs
        .OrderByDescending(x => x.ThoiGianTao)
        .Skip((page - 1) * pageSize)
        .Take(pageSize);

    return query.ToList();
}

public int TongSoTrang(int pageSize)
{
    int total = _db.KhoaHocs.Count();
    return (int)Math.Ceiling((double)total / pageSize);
}

📘 SQL tương đương:

SELECT * FROM KhoaHocs
ORDER BY ThoiGianTao DESC
OFFSET (@page-1)*@pageSize ROWS FETCH NEXT @pageSize ROWS ONLY

🧱 6️⃣ Hàm danh sách trả về ViewModel mới

Khi bạn muốn hiển thị lên giao diện nhưng không cần toàn bộ trường của bảng.

🔹 ViewModel

public class KhoaHocVM
{
    public int ID { get; set; }
    public string TenKhoaHoc { get; set; }
    public string TenChuDe { get; set; }
    public string GiangVien { get; set; }
    public string NgayTaoText { get; set; }
    public string TrangThai { get; set; }
}

🔹 LINQ Select về ViewModel

public List<KhoaHocVM> GetViewModel()
{
    var query = from kh in _db.KhoaHocs
                join cd in _db.ChuDes on kh.idChuDe equals cd.ID into tmp
                from cd in tmp.DefaultIfEmpty() // left join
                orderby kh.ThoiGianTao descending
                select new KhoaHocVM
                {
                    ID = kh.ID,
                    TenKhoaHoc = kh.TenKhoaHoc,
                    TenChuDe = cd != null ? cd.TenChuDe : "(Chưa có chủ đề)",
                    GiangVien = kh.GiangVien,
                    NgayTaoText = kh.ThoiGianTao.HasValue
                        ? kh.ThoiGianTao.Value.ToString("dd-MM-yyyy")
                        : "",
                    TrangThai = kh.isCongKhai == true ? "Công khai" : "Riêng tư"
                };

    return query.ToList();
}

Ưu điểm:

  • Chỉ lấy dữ liệu cần hiển thị.

  • Có thể format trước khi trả ra View (ví dụ: NgayTaoText, TrangThai).

  • Không cần expose toàn bộ Entity ra ngoài.


🧠 Tổng kết bài học

Phần Nội dung Kỹ năng đạt được
1 Tạo Service + DI Tổ chức code sạch, tách tầng dữ liệu
2 Get cơ bản (OrderBy, Count, Sum) Thành thạo LINQ cơ bản
3 Get có Join Truy vấn nhiều bảng
4 Get có Where Lọc dữ liệu động
5 Get có Paging Làm phân trang với LINQ
6 Get ViewModel Tạo dữ liệu tối ưu cho View/UI

 

Bài tập số 13: Hiển thị danh sách dữ liệu bằng LINQ

Yêu cầu:

  1. Hiển thị danh sách tài khoản học viên

    • Truy vấn toàn bộ học viên, lọc theo thông tin, thời gian đăng ký từ ngày đến ngày, trạng thái đăng ký

    • Viết hàm đếm số lượng tổng học viên

  2. Hiển thị danh sách tài khoản quản lý

    • Truy vấn toàn bộ tài khoản, lọc theo thông tin, trạng thái hoạt động

Nộp bài: Tự làm bài cá nhân