我已经看到许多在MVC3应用程序中使用实体框架的例子,它们都是非常简单的演示,只有一个包含edmx的mvc3 Web项目。
因此,他们可以通过"using"语句使用打开和关闭连接的最佳实践:
using(var context = new SchoolEntities())
{
// do some query and return View with result.
}
而且,它可以在"using"语句中正确使用延迟加载(导航属性),因为上下文尚未处置:
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 实例已被释放,不能再用于需要连接的操作。
所以,我必须像这样改变学生DA.cs:
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将像这样更改:
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);
}
}
一切似乎都再次完美,直到它遇到 Update() 方法。
现在,如果我想更新从 BLL 获取的学生对象。FindStudent(),上下文。SaveChanges() 将返回 0,因为上下文已经在 BLL 中释放。FindStudent(),并且不会将任何内容更新到数据库中。
var optStudent = new StudentBO();
var student = optStudent.FindStudent(103);
student.Name = "NewValue";
optStudent.Update(student);
有没有人知道如何在 3 轮胎应用程序中使用 EntityFramework? 或者我如何正确管理上下文。我将在 Web 层中经常使用导航属性,但我不能始终保持连接打开状态以消耗服务器内存。
方法可以处理 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
但我建议你将生命周期管理留给像Autofac,Castle Windsor或Ninject这样的IoC框架,它会自动处理注册的obejcts的创建/处置以及许多其他功能。
感谢您的回答 Kamyar。我在寻找一种简单的策略来管理ObjectContext生命周期而不必使用IoC框架时遇到了这个问题,这对于我的需求来说似乎有点矫枉过正。
我还在这里遇到了您的其他帖子,用于在请求结束时处理上下文。
认为这可能对遇到这种情况的其他人有用,所以只是在这里发布我的代码实现:
上下文管理器类 -
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();
}