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:
-
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
-
-
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
-