如何使用Entity Framework在多层应用程序中正确管理ObjectContext生命周期?

Edi*_*ang 3 entity-framework database-connection

我在MVC3应用程序中看到了很多使用Entity Framework的例子,它们是非常简单的演示,只有一个mvc3 web项目,里面有edmx.

因此,他们可以通过"使用"语句使用开放和关闭连接的最佳实践:

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

并且,它可以正确使用"using"语句中的延迟加载(导航属性),因为上下文尚未处理:

foreach(var item in student.Course)
{
    // do something with the navigation property Course
}
Run Code Online (Sandbox Code Playgroud)

在它成为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.
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,在BLL中,如果我使用:

var student = studentDa.FindStudent(103);
Run Code Online (Sandbox Code Playgroud)

然后调用它的导航属性:

student.Course
Run Code Online (Sandbox Code Playgroud)

我会得到一个错误(当然):

ObjectContext实例已被释放,不能再用于需要连接的操作.

所以,我必须像这样更改StudentDA.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.
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,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);
    }
}
Run Code Online (Sandbox Code Playgroud)

在遇到Update()方法之前,所有事情似乎都是完美的.

现在,如果我想更新一个取自BLL.FindStudent()的学生对象,则context.SaveChanges()将返回0,因为上下文已经在BLL.FindStudent()中处理,并且没有任何内容会更新为数据库.

var optStudent = new StudentBO();
var student = optStudent.FindStudent(103);
student.Name = "NewValue";
optStudent.Update(student);
Run Code Online (Sandbox Code Playgroud)

有没有人知道如何在3轮胎应用中使用EntityFramework?或者我如何正确管理上下文.我将经常在Web层中使用导航属性,但我不能始终保持连接打开以消耗服务器内存.

Kam*_*yar 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;
        }
    }
}  
Run Code Online (Sandbox Code Playgroud)

然后你可以轻松使用:

var ctx = DbContextManager.Current
Run Code Online (Sandbox Code Playgroud)

但我建议你把生命周期管理留给像Autofac,Castle WindsorNinject这样的IoC框架, 它自动处理你注册的obejcts的创建/处理以及许多其他功能.