2012-08-14 35 views
3

我在MVC3應用程序中看到了很多使用實體框架的例子,它們都是非常簡單的演示程序,其中只有一個帶有edmx的mvc3 web項目。如何在使用Entity Framework的多層應用程序中正確管理ObjectContext生命週期?

因此,他們可以通過「使用」語句中使用的打開和關閉連接的最佳做法:

using(var context = new SchoolEntities()) 
{ 
    // do some query and return View with result. 
} 

而且,它可以正確地使用延遲加載(導航屬性)中的「使用」語句內的,因爲上下文尚未 配置:

foreach(var item in student.Course) 
{ 
    // do something with the navigation property Course 
} 

所有的事情似乎是完美的,直到它變成一個n層應用程序。

我創建了DAL,BLL和一個MVC3 UI。

DAL裏面有EDMX,和運營商類,如SchoolDA.cs:

public class StudentDA() 
{ 
    public Student FindStudent(int studentId) 
    { 
     using(var context = new SchoolContext()) 
     { 
      // do query, return a student object. 
     } 
    } 
} 

然後,在BLL,如果我使用:

var student = studentDa.FindStudent(103); 

然後調用它的導航屬性

student.Course 

我會得到(當然)的錯誤:

的ObjectContext的實例已經設置,不能再用於需要連接的操作。

所以,我必須要改變StudentDA.cs這樣的:

public Student FindStudent(int id) 
{ 
    using(var studentDa = new StudentDA()) 
    { 
     // this can access navigation properties without error, and close the connection correctly. 
     return studentDa.FindStudent(id); 
    } 
} 

所有的事情似乎是完美的再次直到滿足:

public class StudentDA() : IDisposable 
{ 
    private SchoolEntites context; 

    public StudentDA() 
    { 
     context = new SchoolEntities(); 
    } 

    public void Dispose() 
    { 
     context.Dispose(); 
    } 

    public Student FindStudent(int studentId) 
    { 
     // do query, return a student object. 
    } 
} 

然後,BLL會喜歡這種改變Update()方法。

現在,如果我想更新是從BLL.FindStudent(),採取context.SaveChanges()將返回0學生對象,因爲上下文已經設置在BLL.FindStudent(),並沒有什麼會更新到數據庫。

var optStudent = new StudentBO(); 
var student = optStudent.FindStudent(103); 
student.Name = "NewValue"; 
optStudent.Update(student); 

有沒有人有關於如何在3輪胎應用中使用EntityFramework的想法?或者我如何正確管理上下文。我將在Web層中經常使用導航屬性,但我不能始終保持連接打開以消耗服務器內存。

+3

搜索_Inversion of Control_和_Dependency Injection_ – Eranga 2012-08-14 04:26:08

+0

@Eranga還確保您保持上下文範圍有限,.InRequestScope或.InTransientScope wit h ninject,這樣可以防止串擾並附加問題 – 2012-08-14 04:34:45

回答

7

處理EF上下文的生命週期有多種方式。在Web應用程序中,通常情況下HttpRequest是唯一的。例如,如果你想在一個Web應用程序手動處理這個問題,有一個每線程/ HttpRequest的EF情況下,你可以用下面的(代碼從http://www.west-wind.com/weblog/posts/2008/Feb/05/Linq-to-SQL-DataContext-Lifetime-Management複製),這樣做的:

internal static class DbContextManager 
{ 
    public static DbContext Current 
    { 
     get 
     { 
      var key = "MyDb_" + HttpContext.Current.GetHashCode().ToString("x") 
         + Thread.CurrentContext.ContextID.ToString(); 
      var context = HttpContext.Current.Items[key] as MyDbContext; 

      if (context == null) 
      { 
       context = new MyDbContext(); 
       HttpContext.Current.Items[key] = context; 
      } 
      return context; 
     } 
    } 
} 

然後您就可以輕鬆使用方法:

var ctx = DbContextManager.Current 

但我建議你離開生命週期管理像AutofacCastle Windsor,或Ninject IoC框架自動處理創建/處理您的註冊obejcts與許多其他功能一起。

+0

如果我使用var key =「foo」,會產生什麼不同?而不是那個長串? Isnt var context = HttpContext.Current.Items [「foo」]是否爲上下文本地? – 2013-09-27 06:15:04

+0

如果您只是處理每上下文的生命週期管理,您的代碼就足夠了(顯然,更易於閱讀)。我已經使用了我從Rick strahl博客獲得的代碼,網址是http://www.west-wind.com/weblog/posts/2008/Feb/05/Linq-to-SQL-DataContext-Lifetime-Management,關於每個上下文/線程生存期管理。 – Kamyar 2013-09-27 06:49:46

+1

看起來很優雅,因爲你使用'Current',看起來會話在請求結束時被清除。謝謝,測試它! – danihp 2013-11-06 11:01:25

0

感謝您的回答Kamyar。我遇到了這個問題,同時尋找一個簡單的策略來管理ObjectContext生命週期,而不必使用IoC框架,這對我的需求似乎有點矯枉過正。

我也遇到了您的其他帖子here,用於在請求結束時處理上下文。

想這可能是別人穿過這個未來,所以只是發表我的實現代碼這裏的有用:

情境管理類 -

internal static class MyDBContextManager 
    { 
     //Unique context key per request and thread 
     private static string Key 
     { 
      get 
      { 
       return string.Format("MyDb_{0}{1}", arg0: HttpContext.Current.GetHashCode().ToString("x"), 
        arg1: Thread.CurrentContext.ContextID); 
      } 
     } 

     //Get and set request context 
     private static MyDBContext Context 
     { 
      get { return HttpContext.Current.Items[Key] as MyDBContext; } 
      set { HttpContext.Current.Items[Key] = value; } 
     } 

     //Context per request 
     public static MyDBContext Current 
     { 
      get 
      { 
       //if null, create new context 
       if (Context == null) 
       { 
        Context = new MyDBContext(); 
        HttpContext.Current.Items[Key] = Context; 
       } 
       return Context; 
      } 
     } 

     //Dispose any created context at the end of a request - called from Global.asax 
     public static void Dispose() 
     { 
      if (Context != null) 
      { 
       Context.Dispose(); 
      } 
    } 
} 

的Global.asax(MVC) -

public override void Init() 
    { 
     base.Init(); 
     EndRequest +=MvcApplication_EndRequest; 
    } 

    private void MvcApplication_EndRequest(object sender, EventArgs e) 
    { 
     MyDBContextManager.Dispose(); 
    } 
相關問題