EntityFramework中的DbContext使用疑點說明

1.DbContext怎麼在Asp.mvc中使用?

  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

2. 不要隨便using或Dispose DbContext會致使延遲加載的不可用,還會有一些其餘錯誤 如IQueryable<T> 下面的方法(.First() /.Count())也不能用。

狀況一:

  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());//能夠返回正確結果。
}

  

3.爲何你要using 或dispose掉DbContext ?

是擔憂數據庫鏈接沒有釋放?仍是擔憂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

相關文章
相關標籤/搜索