【问题标题】:Managing Entity Framework ObjectContext in ASP.NET在 ASP.NET 中管理实体框架 ObjectContext
【发布时间】:2012-01-19 14:30:29
【问题描述】:

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

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

我想知道我应该如何使用ObjectContext

  1. 在每个请求的页面上实例化一个新的ObjectContext,将其作为参数传递给InviteService 类的构造函数,然后在Render 方法中处理它。
  2. 与上述相同,但不是通过构造函数进行设置,而是将其作为参数传递给每个方法。
  3. 在每个方法中使用using 块创建一个单独的Objectcontext

根据 Ladislav 的回答,选项一对我来说似乎是最好的:Entity Framework and Connection Pooling 但选项 3 似乎也有效,因为据我所知,由于连接池,没有建立新的数据库连接。

【问题讨论】:

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


    【解决方案1】:

    为每个 Web 请求创建一个 ObjectContext 并不罕见。我在我的 Web 应用程序中执行此操作。但是,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。该包可确保您的 ObjectContext 在 Web 请求结束时被释放。

    起初这可能看起来很复杂,但这样网页就不必担心创建和处置ObjectContext 的任何细节。

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

    这个建议也适用于 ASP.NET MVC,尽管您不应该在 Controller 的构造函数中调用 Global.GetInstance&lt;IMyService&gt;(),而只需使用构造函数注入(因为 MVC 对此有很好的支持)并使用 MVC3 Integration package

    还可以查看this Stackoverflow question,它讨论了在IObjectContextFactoryObjectContext 之间进行选择。

    【讨论】:

    • +1 用于在每个请求上创建/删除。我这样做的方式相同,并保持简单和干净。
    • 我曾经将IDbContextFactory 注入到我的命令处理程序中,并让处理程序自己处理上下文,但这导致了一个模型,我必须从一个方法到另一个方法,从类传递上下文上课让一切都在相同的上下文中运行,这变成了维护的噩梦。
    • 非常感谢您的回答。依赖注入已经在我的“阅读”列表上一段时间了。在阅读 DI 时,我将使用选项 1。执行操作的逻辑包含在单独的类中,其中每个命令提交数据并根据提交的结果采取进一步的行动。
    【解决方案2】:

    1 是最好的解决方案。 在 NHibernate 世界中称为 session-per-request。

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

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

    只有在 EndRequest 期间,您才能一次性提交所有更改。

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

    假设您有一个带有保存按钮的 Web 表单:

    • 在 BeginRequest 期间创建 ObjectContext
    • 在保存命令处理程序中调用提交
    • 只需在 EndRequest 期间关闭/处置 ObjectContext

    【讨论】:

    • 你怎么知道在 EndRequest 期间什么时候可以提交?
    • 也许我不明白你的问题。当您提交时,您告诉 ORM:“请插入/更新/删除所有待处理的更改”。所以在 EndRequest 中无条件调用 Commit。是考虑到每个被跟踪对象的状态而提交的 ORM。
    • 但是当操作失败时(即抛出异常),在这种情况下你不应该在 EndRequest 期间调用 commit。在这种情况下调用 commit 会破坏系统的原子性。在这种情况下,你如何防止提交被调用?
    • 我明白了,所以有点不同。假设您的 Web 表单上有一个保存按钮。在这种情况下,提交操作在 Save 命令处理程序上,您可以在其中管理异常并可能回滚事务。在 EndRequest 中,您只需要关闭/处置 ObjectContext。
    • 这正是我的意思;-)
    猜你喜欢
    • 2010-09-27
    • 1970-01-01
    • 2013-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-04
    相关资源
    最近更新 更多