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

LINQ to SQL 斷開更新五大解決方案詳解:原理與代碼

     編輯:關於.NET

接上篇「問題重重」,本文詳細剖析五種解決 Attach 異常的方案原理、代碼實現與優缺點,為性能測試奠基。

方案一:重新賦值

查詢原實體,逐屬性覆蓋新值。本質:繞過 Attach,利用上下文跟蹤原實體變更。

var old = db.Products.Single(p => p.ID == new.ID);
old.Name = new.Name; old.Price = new.Price; ...
db.SubmitChanges();
  • 優點:簡單、無異常。
  • 缺點:屬性多時極其繁瑣;反射自動賦值性能差;未使用 LINQ 更新 API,屬妥協。

方案二:禁用對象跟蹤

db.ObjectTrackingEnabled = false 同時關閉 DeferredLoadingEnabled,查詢返回無延遲加載器的實體,Attach(entity, true) 成功。

public Product GetProduct(int id)
{
    var db = new NorthwindDataContext();
    db.ObjectTrackingEnabled = false;
    var loads = new DataLoadOptions();
    loads.LoadWith<Product>(p => p.Category);
    loads.LoadWith<Product>(p => p.Supplier);
    db.LoadOptions = loads;
    return db.Products.SingleOrDefault(p => p.ProductID == id);
}
  • 優點:性能最好,官方推薦提升查詢性能。
  • 缺點:必須在查詢前設置;禁用後不可再 Attach/SubmitChanges;需顯式 LoadWith 載入關聯。

方案三:移除關聯

手動或反射將實體的 EntityRef 置 null、EntitySet 清空,斷開延遲加載器,使 HasDeferredLoaders 為 false。

// 反射通用 Detach
foreach (var fi in entity.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance))
{
    if (fi.FieldType.Name.Contains("EntityRef")) fi.SetValue(entity, null);
    if (fi.FieldType.Name.Contains("EntitySet")) 
    {
        var val = fi.GetValue(entity);
        val?.GetType().GetMethod("Clear")?.Invoke(val, null);
    }
}
  • 優點:保留跟蹤功能,適用於需延遲加載的場景。
  • 缺點:反射開銷;易遺漏字段;屬 Hack 手段。

方案四:使用委托

將查詢謂詞與更新動作封裝在同一 DataContext 實例中執行,完全繞開 Attach。

public void UpdateProduct(Expression<Func<Product,bool>> predicate, Action<Product> action)
{
    using (var db = new NorthwindDataContext())
    {
        var p = db.Products.SingleOrDefault(predicate);
        action(p);
        db.SubmitChanges();
    }
}
// 調用
repo.UpdateProduct(p => p.ID == 1, p => { p.Name = "New"; p.Price = 10; });
  • 優點:性能優、代碼少、無 Attach 問題。
  • 缺點:API 複雜(表達式樹+委托),要求開發者水平高;更新邏輯必須集中在委托塊中,靈活性受限。

方案五:手寫 UPDATE SQL

拼接 SQL,僅更新髒列。屬框架級方案(如 Ezsocio RepositoryBase.UpdateEntity),此處不展開。

小結

各方案各有取捨,下篇將通過性能測試量化差異,給出選型指南。

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