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

LINQ to SQL 多層架構:跨 DataContext 附加實體的正確姿勢

     編輯:關於.NET

在基於 LINQ to SQL 的 N 層架構中,實體從 BLL 傳遞至 DAL 進行更新時,常面臨跨 DataContext 附加的問題。典型流程:

BLL.GetModel(id) → 修改屬性 → BLL.Update(entity) → DAL.Update(entity) → 成功

GetModel 返回後首個 DataContext 即釋放,DAL.Update 又新建一個 DataContext。LINQ to SQL 要求跨 Context 操作先 Attach,再 SubmitChanges。

常見異常與根因

直接 context.User.Attach(entity, true) 會拋出:

「已嘗試 Attach 或 Add 實體,該實體不是新實體,可能是從其他 DataContext 中加載來的……」

根因:實體關聯屬性(EntitySet<Message>、EntityRef<Image> 等)在查詢時未加載,但附加時這些屬性持有對舊 DataContext 的引用,導致 ObjectDisposedException。

解決方案:Detach 斷開舊上下文

在附加前,通過反射清空所有 EntitySet<>、EntityRef<> 字段/屬性,並移除 PropertyChanged/Changing 事件處理器:

public static void Detach<TEntity>(TEntity entity)
{
    Type t = entity.GetType();
    // 清空 EntitySet 屬性
    foreach (var prop in t.GetProperties(BindingFlags.Public | BindingFlags.Instance))
    {
        if (prop.PropertyType.IsGenericType &&
            prop.PropertyType.GetGenericTypeDefinition() == typeof(EntitySet<>))
            prop.SetValue(entity, null, null);
    }
    // 清空 EntityRef 字段
    foreach (var field in t.GetFields(BindingFlags.NonPublic | BindingFlags.Instance))
    {
        if (field.FieldType.IsGenericType &&
            field.FieldType.GetGenericTypeDefinition() == typeof(EntityRef<>))
            field.SetValue(entity, null);
    }
    // 移除事件
    var evtChanged = t.GetEvent("PropertyChanged");
    var evtChanging = t.GetEvent("PropertyChanging");
    if (evtChanged != null) evtChanged.RemoveEventHandler(entity, null);
    if (evtChanging != null) evtChanging.RemoveEventHandler(entity, null);
}

正確流程

  1. GetModel 獲取實體
  2. 調用 Detach(entity) 斷開舊 Context 關聯
  3. 傳遞至 DAL
  4. context.Entity.Attach(entity, true) 附加到新 Context
  5. context.SubmitChanges() 提交更新

此法解決跨層傳遞實體的附加難題,保證多層架構下 LINQ to SQL 正常工作。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved