在 ASP.NET 中管理实体框架 ObjectContext
我正在为 ASP.NET Web 窗体应用程序使用实体框架,我想知道应该如何处理 ObjectContext
及其生命周期。 例如,我有一个 InviteService
类,用于管理邀请,例如创建和接受邀请。该类本身位于 Web 项目的另一个项目/命名空间中。 InviteUsers()
方法为用户列表创建 Invite
实体,调用存储库将它们保存到数据库中,并向每个用户发送邀请链接。
当用户单击邀请按钮时,从 Page
调用该方法。
我想知道如何使用 ObjectContext
- 在每个请求的页面上实例化一个新的
ObjectContext
,并将其作为参数传递给InviteService 的构造函数
类,然后将其处理在Render
方法中。 - 与上面相同,但不是通过构造函数设置它,而是将其作为参数传递给每个方法。
- 使用
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
- Instantiate a new
ObjectContext
on the Page on each Request, passing it as a parameter to the constructor of theInviteService
class and then disposing it in theRender
method. - Same as above but instead of setting it via the constructor, passing it along as a parameter to each method.
- Create a separate
Objectcontext
in each method with ausing
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
每个 Web 请求创建一个
ObjectContext
并不罕见。我在我的网络应用程序中执行此操作。但是,在我看来,页面应该对ObjectContext
一无所知。由于您已经在讨论在服务的构造函数中注入上下文,因此请查看依赖项注入(如果您尚未使用它)。当您使用依赖项注入容器时,您可以让容器为您创建该服务并将对象上下文注入该容器中。您的页面唯一要做的就是从容器请求该服务(理想情况下,您甚至可以将该服务注入到该页面的构造函数中,但这对于 Web 表单来说是不可能的)。
您的页面将如下所示:
在应用程序的启动路径 (Global.asax) 中,您可以像这样配置依赖注入框架:
在这些示例中,我使用了 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 theObjectContext
.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:
In the startup path (Global.asax) of your application, you can configure the Dependency Injection framework like this:
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 yourObjectContext
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 aObjectContext
per request.1 是最佳解决方案。
在 NHibernate 世界中,称为“每次请求会话”。
您可以在 BeginRequest 中实例化 ObjectContext 并在 EndRequest 中刷新/提交它。
1 比 3 更好,因为当请求到达时您就开始使用 ORM(在您的例子中是实体框架)。
然后,您可以在所有页面生命周期中将对象添加到树中、修改类、删除等。
仅在 EndRequest 期间,您仅在一批中提交所有更改。
编辑:正如@Steven所说,对于在提交期间处理异常并不完美。
因此,假设您有一个带有保存按钮的 Web 表单:
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: