首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> 關於ASP.NET

ASP.NET 專案正確使用 Linq to Sql:DataContext 生命週期管理之道

     編輯:關於ASP.NET

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 強型別優勢。

正確模式:請求級 DataContext 單例

// 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() { }
}

業務層取用共享 DataContext


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)。
  • 建議:快取僅存 DTO/匿名型別/純資料類別,不快取 Linq 實體,避免上下文綁定問題。

IQueryable vs IEnumerable 陷阱


// 回傳 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。

總結檢查清單

  1. 專案安裝 DataContextPerRequestModule,確保每請求單一 Context。
  2. 業務層透過 HttpContext.Current.Items 取得共享 Context。
  3. 實體不跨請求快取;跨層傳遞使用 DTO。
  4. Repository 方法回傳 IEnumerable 或具體集合,避免洩漏 IQueryable。
  5. 批次更新/刪除使用 ExecuteCommand 或 SubmitChanges 統一提交。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved