public class Repository { //實例化EF容器:有弊端。一個線程裏可能會建立多個DbContext //DbContext db = new DbContext(); //改造:保證一個請求線程中只有一份EF容器(你要明白:一個url請求到服務器,IIS就開一個線程去處理) protected DbContext GetDbContext { get { //向線程緩存中查詢,若是返回的是null,則建立,同時存入到這個線程緩存中 //注意的是線程緩存CallContext,而不是咱們熟悉的HttpRuntime.cache。意味着這個DbContext對象在這個線程內能被其餘方法共享。 object efDbContext = CallContext.GetData("DbContext"); if (efDbContext == null) { efDbContext = new DbContext(); //存入到這個線程緩存中 CallContext.SetData("DbContext", efDbContext); } return efDbContext as DbContext; } } }
這麼定義以後,全部須要用到DbContext對象的地方,都調這個方法。html
a寫法結果正確ios
PhoneBookEntities phoneBookEntities = new PhoneBookEntities(); var ci = phoneBookEntities.ContactInfo.FirstOrDefault();//這裏並無拿到ci對象裏面的GroupInfo屬性。 if (ci != null) MessageBox.Show(ci.GroupInfo.GroupName);//是延遲加載,訪問 ci.GroupInfo.GroupName 纔會去數據庫查數據
b寫法報錯數據庫
ContactInfo ci = null; using (PhoneBookEntities phoneBookEntities = new PhoneBookEntities()) { ci = phoneBookEntities.ContactInfo.FirstOrDefault(); } if (ci != null) MessageBox.Show(ci.GroupInfo.GroupName); //報錯:此ObjectContext實例已釋放,不可再用於須要鏈接的操做。意味着延遲加載不可用。
a寫法報錯緩存
IQueryable<ContactInfo> ci = null; using (PhoneBookEntities phoneBookEntities = new PhoneBookEntities()) { ci = phoneBookEntities.ContactInfo.Where(c => true); } if (ci != null) MessageBox.Show(ci.Count().ToString());//報錯:提示DbContext已經釋放。
b寫法正確服務器
IQueryable<ContactInfo> ci = null; using (PhoneBookEntities phoneBookEntities = new PhoneBookEntities()) { ci = phoneBookEntities.ContactInfo.Where(c => true); if (ci != null) MessageBox.Show(ci.Count().ToString());//能夠返回正確結果。 }
是擔憂數據庫鏈接沒有釋放?仍是擔憂DbContext佔用過多資源呢?
首先擔憂數據庫鏈接沒有釋放確定是多餘的,由於DbContext在SaveChanges完成後會釋放掉打開的數據庫鏈接。
能夠反編譯一下SaveChages的源碼。
擔憂DbContext佔用過多資源也是多餘的,有GC回收。mvc
結論,You can call Dispose, but in most common scenarios you don’t need to.less
更詳細的能夠看這個英文博客的文章,其中有 Diego Vega (the Senior SDE Lead on EF) 的回信:ide
Hello Jon,this
The default behavior of DbContext is that the underlying connection is automatically opened any time is needed and closed when it is no longer needed. E.g. when you execute a query and iterate over query results using 「foreach」, the call to IEnumerable<T>.GetEnumerator() will cause the connection to be opened, and when later there are no more results available, 「foreach」 will take care of calling Dispose on the enumerator, which will close the connection. In a similar way, a call to DbContext.SaveChanges() will open the connection before sending changes to the database and will close it before returning.url
Given this default behavior, in many real-world cases it is harmless to leave the context without disposing it and just rely on garbage collection.
That said, there are two main reason our sample code tends to always use 「using」 or dispose the context in some other way:
1. The default automatic open/close behavior is relatively easy to override: you can assume control of when the connection is opened and closed by manually opening the connection. Once you start doing this in some part of your code, then forgetting to dipose the context becomes harmful, because you might be leaking open connections.
2. DbContext implements IDiposable following the recommended pattern, which includes exposing a virtual protected Dispose method that derived types can override if for example the need to aggregate other unmanaged resources into the lifetime of the context.
By the way, with DbContext the pattern to open the connection manually and override the automatic open/close behavior is a bit awkward:
((IObjectContextAdapter)dbContext).ObjectContext.Connection.Open()
But we have a bug to make this easier as it used to be with ObjectContext before, e.g.:
dbContext.Database.Connection.Open()
Hope this helps,
Diego
附上參考博客:http://www.cnblogs.com/mecity/archive/2011/07/17/2108508.html