Controller (控制器) → Service/Repository (業務/數據訪問) → Entity (實體類) → View (視圖)
YourDbContext (繼承 DbContext) 及實體類 (如 Product)public class ProductRepository {
private readonly YourDbContext _db = new YourDbContext();
public IEnumerable GetAll() => _db.Products.ToList();
public Product GetById(int id) => _db.Products.Find(id);
// 單元測試時可改為介面 + 依賴注入
}
public class ProductController : Controller {
private readonly ProductRepository _repo = new ProductRepository();
// GET: /Product
public ActionResult Index() {
var list = _repo.GetAll();
return View(list); // 強類型傳遞 IEnumerable
}
// GET: /Product/Details/5
public ActionResult Details(int id) {
var item = _repo.GetById(id);
if (item == null) return HttpNotFound();
return View(item);
}
}
Index.cshtml (列表頁)
@model IEnumerable
ID 名稱 價格 操作
@foreach (var p in Model) {
@p.Id
@p.Name
@p.Price.ToString("C")
@Html.ActionLink("詳情", "Details", new { id = p.Id })
}
Details.cshtml (詳情頁)
@model YourNamespace.Models.Product
- @Html.DisplayNameFor(m => m.Name)
- @Html.DisplayFor(m => m.Name)
- @Html.DisplayNameFor(m => m.Price)
- @Html.DisplayFor(m => m.Price)
Web.config <connectionStrings> 維護,勿硬編碼AddScoped).Include(p => p.Category) 避免 N+1 問題[Required], [StringLength(100)] 等,前端自動生成驗證public ActionResult Index(int page = 1, string keyword = "") {
var query = _repo.GetAll().AsQueryable();
if (!string.IsNullOrEmpty(keyword)) query = query.Where(p => p.Name.Contains(keyword));
var paged = query.OrderBy(p => p.Id).Skip((page-1)*10).Take(10).ToList();
ViewBag.Keyword = keyword;
return View(paged);
}
Database First 流程:EDMX → 實體/Context → Repository → Controller → 強類型 View。**核心在於「強類型模型傳遞」與「關注點分離」**,避免在 View 裡寫 SQL 或商業邏輯。