linq to sql中的自動緩存(對象跟蹤)
linq to sql中的自動緩存(對象跟蹤)
這篇東西應該至少一年前就寫的,不過因為個人太懶,一直沒記下來,今天補上.
linq to sql中,對于同一個DataContext上下文環境,根據表主鍵選擇記錄時(當然這里所指的“記錄”會自動轉成“對象”),如果該記錄已經被select過,默認情況下會被自動緩存下來,下次再選擇時,將自動返回已緩存的對象,而不是重新從數據庫里查詢。
在很多情況下(特別是查詢的場景),這會提高性能(因為避免了數據庫重復查詢),但是也時候也會帶來麻煩:
比如我們取出一個對象后,對其屬性做了修改,然后提交到數據庫前,想比較一下原始記錄,如果某些屬性修改過了,則這樣處理,如果未被修改過,則那樣處理。因為緩存的關系,我們重新取出原始記錄時,其實取出的并不是數據庫中的原始值,而緩存在內存里的對象實例(即修改后的對象 ),所以比較時,永遠都會返回未修改過。
測試原始記錄如下:

測試代碼如下:
using System;
using System.Linq;
using System.Diagnostics;
namespace webApp
{
public partial class Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
dbDataContext db = new dbDataContext();
var u1 = db.Users.FirstOrDefault(c=>c.Id==1);
u1.Photo = "new value";//這里修改了用戶的頭象
var u2 = db.Users.FirstOrDefault(c => c.Id == u1.Id);//重新查詢原始值
if (u2.Photo == u1.Photo)
{
Debug.WriteLine("用戶頭象未被修改!");
}
else
{
Debug.WriteLine("用戶頭象被修改過了!");
//to do list...
//如果保存到數據庫,還應該刪除原來的舊頭象
}
}
}
}
如果運行一下,將永遠得到的都是"用戶頭象未被修改!"。
解決辦法有二個:
1、關閉默認的對象跟蹤
即:
dbDataContext db = new dbDataContext(); db.ObjectTrackingEnabled = false;//關閉默認的對象跟蹤
這個辦法最簡單,但卻是一刀切的辦法,會關閉db所有的緩存功能,在查詢請求遠大于更新請求的場景下,個人并不太喜歡。
2、創建一個新的DataContext上下文來查詢原始值
即:把u2的取值部分改為
User u2 = null;
using (dbDataContext db2 = new dbDataContext()) //創建一個新的上下文
{
u2 = db2.Users.FirstOrDefault(c => c.Id == u1.Id);//重新查詢原始值
}
臨時創建一個db2,然后用它來重新查詢原始值,由于db2是剛創建,之前肯定沒有查詢過Id==u1.id的記錄,所以緩存是空的,因此會到數據庫重新查詢,當然db2用完后,會自動釋放相關資源(using的功勞!)
出處:http://www.rzrgm.cn/yjmyzz/archive/2010/08/24/1807271.html
浙公網安備 33010602011771號