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

发布于 2024-12-27 20:52:48 字数 798 浏览 2 评论 0原文

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

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

我想知道如何使用 ObjectContext

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

根据拉迪斯拉夫的回答,选项一对我来说似乎最好: 实体框架和连接池化 但选项 3 似乎也有效,因为据我所知,由于连接池,没有建立新的数据库连接。

I'm using the Entity Framework for an ASP.NET Web Forms application and I'm wondering how I should deal with ObjectContext and it's lifetime.
For example, I have an InviteService class that manages invites such as creating and accepting invites. The class itself is in another project/namespace from the Web project.
An InviteUsers() method creates Invite entities for a list of users, calls a repository to save them to the database and mails each user an invite link.

The method is called from the Page when a user clicks the invite button.

I would like to know how I should use the ObjectContext

  1. Instantiate a new ObjectContext on the Page on each Request, passing it as a parameter to the constructor of the InviteService class and then disposing it in the Render method.
  2. Same as above but instead of setting it via the constructor, passing it along as a parameter to each method.
  3. Create a separate Objectcontext in each method with a using block.

Option one seems best to me based on the answer of Ladislav here: Entity Framework and Connection Pooling
But option 3 seems valid as well since as far as I know, no new database connections are made because of connection pooling.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

a√萤火虫的光℡ 2025-01-03 20:52:48

每个 Web 请求创建一个 ObjectContext 并不罕见。我在我的网络应用程序中执行此操作。但是,在我看来,页面应该对 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 不是核心库的一部分,但 可用作(NuGet) 扩展包。该包确保您的 ObjectContext 在 Web 请求结束时被释放。

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

此外,将执行用例的逻辑放置在单个类中:命令。让命令(或系统)确保该操作的原子性。不要让页面对此负责,也不要在请求结束时提交,因为那时您将不知道是否可以调用 commit。不,让命令自己处理这个问题。这是一篇关于编写业务命令的文章

此建议也适用于 ASP.NET MVC,尽管您不应该在 Controller 的构造函数内调用 Global.GetInstance(),而只需使用构造函数注入(因为 MVC 对此有很好的支持)并使用 MVC3 集成包

另请查看这个 Stackoverflow 问题,其中讨论了在每个请求使用 IObjectContextFactory 或使用 ObjectContext 之间进行选择。

It is not unusual to create a single ObjectContext per web request. I do this in my web applications. However, IMO, the page should know nothing about the ObjectContext.

Since you are already talking about injecting the context in the constructor of the service, take a look at dependency injection (if you aren't using that already). When you use a dependency injection container, you can let the container create that service for you and inject the object context in that container. The only thing your page has to do is request that service from the container (ideally, you would even let that service be injected in the constructor of that page, but this is not possible with web forms).

Your page would look like this:

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);
    }
}

In the startup path (Global.asax) of your application, you can configure the Dependency Injection framework like this:

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;
}

In these examples I used the Simple Injector dependency injection container, although any DI container will do. The RegisterPerWebRequest is not part of the core library, but is available as (NuGet) extension package. The package ensures that your ObjectContext is disposed when the web request ends.

This might seem complex at first, but this way the web page doesn't have to worry at all about any details of creating and disposing an ObjectContext.

Further, place the logic that executes a use case in a single class: a command. Let the command (or the system) ensure atomicness of that operation. Don't let the page be responsible for this, and don't commit on the end of the request, because at that point you won't know if it is even OK to call commit. No, let the command handle this itself. Here is an article about writing business commands.

This advice holds for ASP.NET MVC as well, although you should not call Global.GetInstance<IMyService>() inside the Controller's constructor, but simply use constructor injection (since MVC has great support for this) and use the MVC3 Integration package.

Also take a look at this Stackoverflow question, which talks about choosing between a IObjectContextFactory or having a ObjectContext per request.

紫﹏色ふ单纯 2025-01-03 20:52:48

1 是最佳解决方案。
在 NHibernate 世界中,称为“每次请求会话”。

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

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

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

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

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

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

1 is best solution.
In NHibernate world is called session-per-request.

You can instantiate ObjectContext in BeginRequest and flush/commit it in EndRequest.

1 is better than 3 because you start working with ORM (Entity Framework in your case) when a request arrives.
Then you add object to the tree, modify class, delete and so on during ALL page lifecycle.

Only during EndRequest you commit ALL your changes in one batch only.

EDIT: as @Steven says is not perfect for dealing with exception during commit.

So suppose you have a web form with a save button:

  • create ObjectContext during BeginRequest
  • call commit in Save command handler
  • simply close/dispose ObjectContext during EndRequest
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文