在ASP.NET中管理实体框架ObjectContext

时间:2012-01-19 14:30:30

标签: asp.net .net entity-framework ado.net objectcontext

我正在使用ASP.NET Web窗体应用程序的实体框架,我想知道我应该如何处理ObjectContext并且它的生命周期。 例如,我有一个InviteService类来管理邀请,例如创建和接受邀请。该类本身位于Web项目的另一个项目/命名空间中。 InviteUsers()方法为用户列表创建Invite个实体,调用存储库将其保存到数据库,并向每个用户邮寄邀请链接。

当用户点击邀请按钮时,会从Page调用该方法。

我想知道如何使用ObjectContext

  1. 在每个请求的页面上实例化一个新的ObjectContext,将其作为参数传递给InviteService类的构造函数,然后将其置于Render方法中。
  2. 与上述相同,但不是通过构造函数设置它,而是将其作为参数传递给每个方法。
  3. 在每个方法中使用Objectcontext块创建单独的using
  4. 根据Ladislav的答案,选项一对我来说似乎最好:Entity Framework and Connection Pooling 但是选项3似乎也是有效的,因为据我所知,由于连接池没有建立新的数据库连接。

2 个答案:

答案 0 :(得分:6)

每个网络请求创建一个ObjectContext并不罕见。我在我的网络应用程序中这样做。但是,IMO,页面应该对ObjectContext一无所知。

由于您已经在讨论在服务的构造函数中注入上下文,请查看依赖注入(如果您尚未使用它)。使用依赖项注入容器时,可以让容器为您创建该服务,并在该容器中注入对象上下文。您的页面唯一要做的就是从容器中请求该服务(理想情况下,您甚至可以将该服务注入该页面的构造函数中,但这对于Web表单是不可能的。)

您的页面如下所示:

public class MyPage : Page
{
    private readonly IMyService service;

    public MyPage()
    {
        this.service = Global.GetInstance<IMyService>();
    }

    protected void Btn1_OnClick(object s, EventArgs e)
    {
        this.service.DoYourThing(this.TextBox1.Text);
    }
}

在应用程序的启动路径(Global.asax)中,您可以像这样配置依赖注入框架:

private static Container Container;

public static T GetInstance<T>() where T : class
{
    return container.GetInstance<T>();
}

void Application_Start(object sender, EventArgs e) 
{
    var container = new Container();

    string connectionString = ConfigurationManager
        .ConnectionStrings["MyCon"].ConnectionString;

    // Allow the container to resolve your context and
    // tell it to create a single instance per request.
    container.RegisterPerWebRequest<MyContext>(() =>
        new MyContext(connectionString));

    // Tell the container to return a new instance of
    // MyRealService every time a IMyService is requested.
    // When MyContext is a constructor argument, it will
    // be injected into MyRealService.
    container.Register<IMyService, MyRealService>();

    Container = container;
}

在这些示例中,我使用了Simple Injector依赖注入容器,尽管任何DI容器都可以。 RegisterPerWebRequest不是核心库的一部分,而是is available as (NuGet) extension package。该程序包可确保在Web请求结束时处置ObjectContext

这一开始可能看起来很复杂,但这样一来,网页就不必担心创建和部署ObjectContext的任何细节。

此外,将执行用例的逻辑放在单个类中:命令。让命令(或系统)确保该操作的原子性。不要让页面对此负责,并且不要在请求结束时提交,因为此时您不会知道是否可以调用commit。不,让命令自己处理。这是an article about writing business commands

这个建议也适用于ASP.NET MVC,虽然你不应该在Controller的构造函数中调用Global.GetInstance<IMyService>(),但只需使用构造函数注入(因为MVC对此有很大的支持)并使用{{3} }。

另请参阅MVC3 Integration package,其中介绍了在IObjectContextFactory或每次请求ObjectContext之间进行选择。

答案 1 :(得分:2)

1是最佳解决方案。 在NHibernate中,world被称为session-per-request。

您可以在BeginRequest中实例化ObjectContext并在EndRequest中刷新/提交它。

1优于3,因为您在请求到达时开始使用ORM(在您的情况下为实体框架)。 然后在整个页面生命周期中向树中添加对象,修改类,删除等等。

仅在EndRequest期间,您只能在一个批次中提交所有更改。

编辑:正如@Steven所说,在提交期间处理异常并不完美。

假设你有一个带有保存按钮的网络表单:

  • 在BeginRequest期间创建ObjectContext
  • 在“保存命令处理程序”中调用提交
  • 在EndRequest期间简单地关闭/处置ObjectContext