Linq to Sql 核心在於 DataContext 與實體類別。許多開發者習慣 using (var db = new DataContext()) 短暫建立,導致實體脫離上下文、延遲載入失效、重複查詢。本文深入剖析 DataContext 生命週期管理正確模式:請求級單例、實體附加/分離、快取策略。
// 錯誤:每個方法獨立 DataContext
public UserInfo GetUser(int id) {
using (var db = new MyDataContext())
return db.Users.FirstOrDefault(u => u.Id == id);
}
public CompanyInfo GetCompany(UserInfo user) {
using (var db = new MyDataContext()) // user 已脫離此 Context
return db.Companies.FirstOrDefault(c => c.Id == user.CompanyId); // 需重新查詢 user
}
結果:實體脫離原 DataContext,導航屬性 (user.Company) 無法延遲載入,業務層被迫改用 ID 傳遞,喪失 Linq 強型別優勢。
// HttpModule 或 Global.asax
public class DataContextPerRequestModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.BeginRequest += (s, e) => HttpContext.Current.Items["DataContext"] = new MyDataContext();
context.EndRequest += (s, e) =>
{
if (HttpContext.Current.Items["DataContext"] is MyDataContext db)
{
db.SubmitChanges(); // 統一提交
db.Dispose();
}
};
}
public void Dispose() { }
}
public class UserService
{
private MyDataContext Db => (MyDataContext)HttpContext.Current.Items["DataContext"];
public UserInfo GetUser(int id) => Db.Users.FirstOrDefault(u => u.Id == id);
public CompanyInfo GetCompany(UserInfo user) => user.Company; // 直接導航,延遲載入生效
public IEnumerable GetTransactions(CompanyInfo company)
=> Db.Transactions.Where(t => t.CompanyId == company.Id); // 同一 Context,可組合查詢
}
Cache/Session 前需 db.Detach(entity) (Linq to Sql 無內建 Detach,需序列化/反序列化或手動斷開關聯)。db.Users.Attach(entity, originalEntity) 或 db.Refresh(RefreshMode.KeepCurrentValues, entity)。
// 回傳 IQueryable:查詢延遲執行,呼叫端可再加 Where/OrderBy,但必須在同一 Context 存活期間枚舉
public IQueryable GetActiveUsers() => Db.Users.Where(u => u.IsActive);
// 回傳 IEnumerable/IList:立即執行 (ToList),脫離 Context 後仍可使用,但失去延遲查詢優勢
public IEnumerable GetActiveUsersList() => Db.Users.Where(u => u.IsActive).ToList();
原則:Repository 回傳 IEnumerable/IList,封裝查詢細節;僅在同一業務邏輯內組合查詢時 內部使用 IQueryable。
DataContextPerRequestModule,確保每請求單一 Context。HttpContext.Current.Items 取得共享 Context。IEnumerable 或具體集合,避免洩漏 IQueryable。ExecuteCommand 或 SubmitChanges 統一提交。