C# 我什么时候应该创建一个新的 DbContext()
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13551100/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
When should I create a new DbContext()
提问by JensB
I am currently using a DbContextsimilar to this:
我目前正在使用DbContext类似的:
namespace Models
{
public class ContextDB: DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<UserRole> UserRoles { get; set; }
public ContextDB()
{
}
}
}
I am then using the following line at the top of ALLmy controllers that need access to the database. Im also using it in my UserRepository Class which contains all methods relating to the user (such as getting the active user, checking what roles he has, etc..):
然后我在需要访问数据库的所有控制器的顶部使用以下行。我也在我的 UserRepository 类中使用它,其中包含与用户相关的所有方法(例如获取活动用户,检查他拥有哪些角色等):
ContextDB _db = new ContextDB();
Thinking about this.. there are occations when one visitor can have multiple DbContexts active.. ie. if hes visiting a controller that uses the UserRepository.. this might not be the best of ideas, and I've got a few questions about it
考虑到这一点.. 有时一个访问者可以有多个 DbContext 处于活动状态.. 即。如果他正在访问使用 UserRepository 的控制器..这可能不是最好的主意,我对此有一些疑问
- When should I make a new DbContext / should I have one global context that I pass around?
- Can i have one global Context that I reuse in all places?
- Does this cause a performance hit?
- How is everyone else doing this?
- 我什么时候应该创建一个新的 DbContext/我应该有一个我传递的全局上下文?
- 我可以拥有一个可以在所有地方重复使用的全局上下文吗?
- 这会导致性能下降吗?
- 其他人是如何做到这一点的?
采纳答案by Benjamin Gale
I use a base controller that exposes a DataBaseproperty that derived controllers can access.
我使用了一个基础控制器,它公开了一个DataBase派生控制器可以访问的属性。
public abstract class BaseController : Controller
{
public BaseController()
{
Database = new DatabaseContext();
}
protected DatabaseContext Database { get; set; }
protected override void Dispose(bool disposing)
{
Database.Dispose();
base.Dispose(disposing);
}
}
All of the controllers in my application derive from BaseControllerand are used like this:
我的应用程序中的所有控制器都源自BaseController并使用如下:
public class UserController : BaseController
{
[HttpGet]
public ActionResult Index()
{
return View(Database.Users.OrderBy(p => p.Name).ToList());
}
}
Now to answer your questions:
现在回答您的问题:
When should I make a new DbContext / should I have one global context that I pass around?
我什么时候应该创建一个新的 DbContext/我应该有一个我传递的全局上下文?
The context should be created per request. Create the context, do what you need to do with it then get rid of it. With the base class solution I use you only have to worry about using the context.
应根据请求创建上下文。创建上下文,做你需要做的事情,然后摆脱它。使用我使用的基类解决方案,您只需担心使用上下文。
Do not try and have a global context (this is not how web applications work).
不要尝试使用全局上下文(这不是 Web 应用程序的工作方式)。
Can I have one global Context that I reuse in all places?
我可以拥有一个可以在所有地方重复使用的全局上下文吗?
No, if you keep a context around it will keep track of all the updates, additions, deletes etc and this will slow your application down and may even cause some pretty subtle bugs to appear in your application.
不,如果您保持上下文,它将跟踪所有更新、添加、删除等,这会减慢您的应用程序速度,甚至可能导致您的应用程序中出现一些非常微妙的错误。
You should probably chose to either expose your repository oryour Context to your controller but not both. Having two contexts being access from the same method is going to lead to bugs if they both have different ideas about the current state of the application.
您可能应该选择将您的存储库或您的上下文公开给您的控制器,但不能同时公开。如果两个上下文对应用程序的当前状态有不同的看法,那么从同一个方法访问两个上下文将导致错误。
Personally, I prefer to expose DbContextdirectly as most repository examples I have seen simply end up as thin wrappers around DbContextanyway.
就我个人而言,我更喜欢DbContext直接公开,因为我所看到的大多数存储库示例DbContext无论如何最终都只是简单的包装器。
Does this cause a performance hit?
这会导致性能下降吗?
The first time a DbContextis created is pretty expensive but once this has been done a lot of the information is cached so that subsequent instantiations are a lot quicker. you are more likely to see performance problems from keeping a context around than you are from instantiating one each time you need access to your database.
第一次DbContext创建a非常昂贵,但是一旦完成,很多信息都会被缓存,以便后续实例化更快。与每次需要访问数据库时实例化上下文相比,保持上下文更可能导致性能问题。
How is everyone else doing this?
其他人是如何做到这一点的?
It depends.
这取决于。
Some people prefer to use a dependency injection framework to pass a concrete instance of their context to their controller when it is created. Both options are fine. Mine is more suitable for a small scale application where you know the specific database being used isn't going to change.
有些人更喜欢使用依赖注入框架在创建时将其上下文的具体实例传递给控制器。这两个选项都不错。我的更适合小型应用程序,您知道正在使用的特定数据库不会改变。
some may argue that you can'tknow this and that is why the dependency injection method is better as it makes your application more resilient to change. My opinion on this is that it probably won't change (SQL server & Entity Framework are hardly obscure) and that my time is best spent writing the code that is specific to my application.
有些人可能会争辩说您无法知道这一点,这就是依赖注入方法更好的原因,因为它使您的应用程序更能适应变化。我对此的看法是它可能不会改变(SQL 服务器和实体框架几乎不模糊)并且我的时间最好花在编写特定于我的应用程序的代码上。
回答by Andrew
Right now I am trying this approach, which avoids instantiating the context when you call actions that don't use it.
现在我正在尝试这种方法,它可以避免在调用不使用它的操作时实例化上下文。
public abstract class BaseController : Controller
{
public BaseController() { }
private DatabaseContext _database;
protected DatabaseContext Database
{
get
{
if (_database == null)
_database = new DatabaseContext();
return _database;
}
}
protected override void Dispose(bool disposing)
{
if (_database != null)
_database.Dispose();
base.Dispose(disposing);
}
}
回答by CSharper
This is obviously an older question but if your using DI you can do something like this and scope all your objects for the lifetime of the request
这显然是一个较旧的问题,但是如果您使用 DI,您可以执行类似的操作并在请求的生命周期内确定所有对象的范围
public class UnitOfWorkAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var context = IoC.CurrentNestedContainer.GetInstance<DatabaseContext>();
context.BeginTransaction();
}
public override void OnActionExecuted(HttpActionExecutedContext actionContext)
{
var context = IoC.CurrentNestedContainer.GetInstance<DatabaseContext>();
context.CloseTransaction(actionContext.Exception);
}
}
回答by Ravior
I try to answer out of my own experience.
我试着根据我自己的经验来回答。
1. When should I make a new DbContext / should I have one global context that I pass around?
1. 我什么时候应该创建一个新的 DbContext / 我应该有一个我传递的全局上下文吗?
The Context should be injected by the dependency-injection and should not be instantiated by yourself. Best-Practice is to have it created as a scoped service by the dependency-injection. (See my answer to Question 4)
Context 应该通过依赖注入来注入,而不应该自己实例化。最佳实践是通过依赖注入将其创建为范围服务。(见我对问题4的回答)
Please also consider using a proper layered application structure like Controller > BusinessLogic > Repository. In this case it would not be the case that your controller receives the db-context but the repository instead. Getting injected / instantiating a db-context in a controller tells me that your application architecture mixes many responsibilities in one place, which - under any circumstances - I cannot recommend.
还请考虑使用适当的分层应用程序结构,例如 Controller > BusinessLogic > Repository。在这种情况下,您的控制器不会收到 db-context 而是存储库。在控制器中注入/实例化 db-context 告诉我,您的应用程序架构在一个地方混合了许多职责,在任何情况下 - 我都不能推荐。
2. Can i have one global Context that I reuse in all places?
2. 我可以拥有一个可以在所有地方重复使用的全局上下文吗?
Yes you can havebut the question should be "ShouldI have..." -> NO. The Context is meant to be used per request to change your repository and then its away again.
是的,您可以拥有,但问题应该是“我应该拥有...”-> 否。上下文旨在用于每个请求来更改您的存储库,然后再次离开。
3. Does this cause a performance hit?
3. 这会导致性能下降吗?
Yes it does because the DBContext is simply not made for being global. It stores all the data that has been entered or queried into it until it is destroyed. That means a global context will get larger and larger, operations on it will get slower and slower until you will get an out of memory exceptions or you die of age because it all slowed to a crawl.
是的,因为 DBContext 并不是为全局而设计的。它存储所有已经输入或查询到其中的数据,直到它被销毁。这意味着全局上下文将变得越来越大,对它的操作将变得越来越慢,直到您遇到内存不足异常或您因年老而死,因为这一切都变慢了。
You will also get exceptions and many errors when multiple threads access the same context at once.
当多个线程同时访问同一个上下文时,您还将收到异常和许多错误。
4. How is everyone else doing this?
4. 其他人是如何做到这一点的?
DBContext injected through dependency-injection by a factory; scoped:
DBContext 由工厂通过依赖注入注入;范围:
services.AddDbContext<UserDbContext>(o => o.UseSqlServer(this.settings.DatabaseOptions.UserDBConnectionString));
I hope my answers where of help.
我希望我的回答有帮助。
回答by Gregory Khrapunovich
You should dispose the context immediately after each Save() operation. Otherwise each subsequent Save will take longer. I had an project that created and saved complex database entities in a cycle. To my surprise, the operation became three times faster after I moved "using (var ctx = new MyContext()){...}" inside the cycle.
您应该在每次 Save() 操作之后立即处理上下文。否则每次后续保存将花费更长的时间。我有一个项目,它在一个循环中创建和保存复杂的数据库实体。令我惊讶的是,在循环中移动“使用(var ctx = new MyContext()){...}”后,操作速度提高了三倍。

