閱讀目錄:數據庫
1、什麼是Identity map模式緩存
2、關於Identity map模式的驗證示例ide
3、Unit of Work 模式spa
4、總結和注意的問題.net
Identity map是EF獲取和緩存數據的模式。
Identity map模式指的是任何數據都只會被加載一次,以map的形式緩存,以惟一的identity來再次獲取這些數據。
在EF中,就是在一個Context的生命週期中,全部查詢過的數據都會緩存到Context的local中緩存。當再次訪問這些數據的時候,就會以主鍵(identity)從緩存中獲取這些數據。3d
看看下面這段代碼運行的結果:code
using (var context = new SchoolContext()) { result1 = context.Students.ToList(); result1[0].Age = -1; result2 = context.Students.ToList(); var s1 = context.Students.First(s => s.Id == 1); var s2 = context.Students.First(s => s.Id == 1); var s3 = context.Students.First(s => s.Id == 3); var s4 = context.Students.First(s => s.Id == 3); Debug.Assert(ReferenceEquals(s1, s2)); Debug.Assert(ReferenceEquals(s3, s4)); }
運行以後,會發現s1和s2是同一個引用,s3和s4也是同一個引用。
緣由就是在Identity map模式來講,對於惟一的主鍵,返回的必然是同一個對象。對象
再來看一個更加有趣的例子blog
public IEnumerable<Student> GetStudents() { List<Student> result1; List<Student> result2; using (var context = new SchoolContext()) { result1 = context.Students.ToList(); result1[0].Age = -1; result2 = context.Students.ToList(); } return result2; }
實際的數據庫中的result1[0].Age是18,若是修改Age是-1, 再次執行context.Students.ToList(), 返回數據的Age並非數據庫中的18,而是-1.生命週期
可是根據MiniProfiler的監控結果,EF的確訪問了2次數據庫
從這裏,得出的結論是:
Context在一次查詢結束後,獲得的數據會保存到本地緩存,在提交以前對數據的修改都是在本地進行。
當再次Qeury的時候,Context中不存在的數據會放到Context中,Context已經存在的數據(即便被修改了),也不會被數據庫的數據覆蓋。
Unit of Work模式指的是:
全部對於context中查詢獲得的實體對象的數據修改,都只會在調用SaveChanges方法後,纔會真正的保存到數據庫中。你能夠在一個Context的生命週期中,修改多個實體對象的值,而後一次提交保存。
在EF中,因爲Unit of Work模式,沒有辦法作選擇性的保存數據,只要是數據發生了改動,都會在SaveChnage方法中一併提交到數據庫中保存。
結合這兩種模式,能夠看出
在一個Context的生命週期中,一個Entity只會有一個實例,任何對該實例的修改,即便這些改動沒有保存到數據庫中,修改都會影響到整個Context的生命週期。
注意問題:
1. 在使用EF的時候,理想的方式應該是 獲取數據-> 修改數據,保存數據->獲取數據……的過程。
不要在修改數據的過程當中,再次請求數據,由於這些數據極可能和數據庫中的數據不一致。
2. 在顯示層,最好使用ViewModel, 而不要直接使用EF中Model.
好比一篇博客文章中,我只想顯示前500個字給非註冊用戶看,若是使用Model, 不當心直接將文章內容的字段修改了,只保留了500個字,而後最後調用了SaveChange,用來保存文章的閱讀次數。
這樣就會致使文章內容被我不當心給丟失了。
下篇討論如何在Asp.net MVC中實現One Context Per Request