程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> LINQ那些事兒(6)-對象生命周期管理

LINQ那些事兒(6)-對象生命周期管理

編輯:關於.NET

為了實現從”LINQ那些事”(1)-(5)中介紹的查詢特性,在從數據庫獲取數據至返回給用戶之間,除了O/R Mapping外,LINQ2SQL內建了對象標識緩存和跟蹤等服務。本文無意討論這些服務實現的細節,但是稍微了解這些服務有助於我們更有效的使用LINQ,並且為自己編寫LINQ擴展提供參考。

對象標識緩存(identity caching)

讓我們來看看對象標識緩存(identity caching)的第一個好處:

01 var context = GenerateContext();
02 context.Log = Console.Out;
03 var query1 =
04     (from c in context.Customers
05      select c).Take(100);
06
07 var watch = new Stopwatch();
08 watch.Start();
09 query1.ToList();
10 watch.Stop();
11 watch.ElapsedMilliseconds.Dump();
12
13 watch.Reset();
14 watch.Start();
15 query1.ToList();
16 watch.Stop();
17 watch.ElapsedMilliseconds.Dump();

查詢Northwnd的Customers表的100條記錄,兩處的query1.ToList()都執行了兩桶的數據庫查詢操作,但是兩處的時間有差別。看看輸出結果:

01 SELECT TOP (100) [t0].[CustomerID], [t0].[CompanyName], [t0].[ContactName], [t0]
02 .[ContactTitle], [t0].[Address], [t0].[City], [t0].[Region], [t0].[PostalCode],
03 [t0].[Country], [t0].[Phone], [t0].[Fax], [t0].[CustomerGuid]
04 FROM [dbo].[Customers] AS [t0]
05 -- Context: SqlProvider(Sql2008) Model: MappedMetaModel Build: 3.5.30729.1
06
07 1058
08 SELECT TOP (100) [t0].[CustomerID], [t0].[CompanyName], [t0].[ContactName], [t0]
09 .[ContactTitle], [t0].[Address], [t0].[City], [t0].[Region], [t0].[PostalCode],
10 [t0].[Country], [t0].[Phone], [t0].[Fax], [t0].[CustomerGuid]
11 FROM [dbo].[Customers] AS [t0]
12 -- Context: SqlProvider(Sql2008) Model: MappedMetaModel Build: 3.5.30729.1
13
14 3

第一次查詢用了1058毫秒,而第二次查詢只花了3毫秒!

這樣的情況的前提是發生在同一個DataContext對象上的查詢。當從數據庫查詢返回後,LINQ需要做O/R mapper,這時會先檢查緩存中PrimaryKey相同的對象是否已經存在,如果已經存在,則不再對該條數據做映射,避免了重復映射。而作為 identity caching的唯一標識就是Primary Key,這就是定義enitity class時必須定義IsPrimaryKey的Column的原因之一。

對象緩存的第二個好處就是避免了同一個DataContext在SubmitChanges時發生optimistic concurrency的情況,相關例子在“LINQ那些事(4)”中已經提過。

很多人會質疑O/R Mapping框架在運行時通過反射來映射對象,會造成性能的降低。這個問題是不可避免的,問題是影響的程度,LINQ2SQL我還沒有在具體的項目中應用,問了TerryLee他的項目也沒在用,希望有應用經驗的朋友能告訴我一下。

改變跟蹤(change tracking)

同樣的先由一段代碼,我們看看change tracking的好處:

1 var context = GenerateContext();
2 context.Log = Console.Out;
3 var query =
4     (from c in context.Products
5      select c).First();
6 query.ProductName = "foo";
7 context.SubmitChanges();

代碼從northwnd數據庫中取出一條product記錄,修改了ProductName後提交數據庫保存,看看輸出的SQL語句:

01 UPDATE [dbo].[Products]
02 SET [ProductName] = @p9
03 WHERE ([ProductID] = @p0) AND ([ProductName] = @p1) AND ([SupplierID] = @p2) AND
04  ([CategoryID] = @p3) AND ([QuantityPerUnit] = @p4) AND ([UnitPrice] = @p5) AND
05 ([UnitsInStock] = @p6) AND ([UnitsOnOrder] = @p7) AND ([ReorderLevel] = @p8) AND
06  (NOT ([Discontinued] = 1))
07 -- @p0: Input Int (Size = 0; Prec = 0; Scale = 0) [1]
08 -- @p1: Input NVarChar (Size = 4; Prec = 0; Scale = 0) [Chai]
09 -- @p2: Input Int (Size = 0; Prec = 0; Scale = 0) [1]
10 -- @p3: Input Int (Size = 0; Prec = 0; Scale = 0) [1]
11 -- @p4: Input NVarChar (Size = 18; Prec = 0; Scale = 0) [10 boxes x 20 bags]
12 -- @p5: Input Money (Size = 0; Prec = 19; Scale = 4) [18.0000]
13 -- @p6: Input SmallInt (Size = 0; Prec = 0; Scale = 0) [39]
14 -- @p7: Input SmallInt (Size = 0; Prec = 0; Scale = 0) [0]
15 -- @p8: Input SmallInt (Size = 0; Prec = 0; Scale = 0) [10]
16 -- @p9: Input NVarChar (Size = 3; Prec = 0; Scale = 0) [foo]
17 -- Context: SqlProvider(Sql2008) Model: MappedMetaModel Build: 3.5.30729.1

SET語句中只包含已修改的屬性,優化了UPDAte語句;Where語句為原始值和數據庫值的比較,實現了並發檢測。

在返回查詢對象之前,DataContext會保存一份對象的copy,並通過change tracking獲知對象發生修改,基於這兩點DataContext才能生成上面的SQL語句。

在DataContext對象的生命周期內,identity caching和change tracking給我們不少好處,但是這樣的好處是以犧牲少許性能為代價的,對於常用的查詢-顯示模式的應用,可以通過關閉這兩個服務來提高性能。

1 context.ObjectTrackingEnabled = false;

另外一個可提高性能的方法是關閉Lazy-Loading

1 context.DeferredLoadingEnabled = false;

但是因為條件限制,我沒有能比較關閉這兩項後的性能差異,希望知道知道的朋友告訴我一下,謝謝!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved