C# 我应该在什么时候创建一个新的DbContext()
我目前使用的C# 我应该在什么时候创建一个新的DbContext(),c#,asp.net-mvc,entity-framework,asp.net-mvc-4,C#,Asp.net Mvc,Entity Framework,Asp.net Mvc 4,我目前使用的DbContext与此类似: namespace Models { public class ContextDB: DbContext { public DbSet<User> Users { get; set; } public DbSet<UserRole> UserRoles { get; set; } public ContextDB() {
DbContext
与此类似:
namespace Models
{
public class ContextDB: DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<UserRole> UserRoles { get; set; }
public ContextDB()
{
}
}
}
考虑到这一点,有时一个访问者可以激活多个DBContext,例如,如果它正在访问使用UserRepository的控制器,这可能不是最好的主意
我应该什么时候创建一个新的DbContext?或者,我是否应该拥有一个在所有地方传递和重用的全局上下文?这会导致性能下降吗?也欢迎提供其他方法的建议。我使用的基本控制器公开派生控制器可以访问的
数据库
属性
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);
}
}
我的应用程序中的所有控制器都源自BaseController
,使用方式如下:
public class UserController : BaseController
{
[HttpGet]
public ActionResult Index()
{
return View(Database.Users.OrderBy(p => p.Name).ToList());
}
}
现在回答您的问题:
我应该什么时候创建一个新的DbContext/我应该有一个全局上下文吗
我传来传去
应该为每个请求创建上下文。创建上下文,做你需要做的事情,然后摆脱它。对于我使用的基类解决方案,您只需担心使用上下文
不要尝试使用全局上下文(这不是web应用程序的工作方式)
我可以拥有一个在所有地方重复使用的全局上下文吗
不,如果你保持一个上下文,它将跟踪所有的更新、添加、删除等,这将减慢你的应用程序,甚至可能导致一些非常微妙的错误出现在你的应用程序中
您可能应该选择将存储库或上下文公开给控制器,但不能同时公开两者。如果两个上下文对应用程序的当前状态有不同的看法,那么从同一方法访问两个上下文将导致错误
就我个人而言,我更喜欢直接公开DbContext
,因为我所看到的大多数存储库示例最终都只是作为DbContext
的薄包装
这会导致性能下降吗
第一次创建DbContext
非常昂贵,但一旦创建完成,就会缓存大量信息,以便后续的实例化更快。与每次需要访问数据库时实例化一个上下文相比,保留上下文更有可能导致性能问题
其他人是怎么做到的
视情况而定
有些人更喜欢使用依赖项注入框架,在创建上下文的具体实例时将其传递给控制器。两种选择都可以。我的更适合于小规模应用程序,您知道所使用的特定数据库不会改变
有些人可能会争辩说,您不知道这一点,这就是为什么依赖项注入方法更好,因为它使您的应用程序更能适应变化。我的观点是,它可能不会改变(SQL server&Entity Framework很难模糊),我的时间最好花在编写特定于我的应用程序的代码上。现在我正在尝试这种方法,这样可以避免在调用不使用上下文的操作时实例化上下文
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);
}
}
这显然是一个较老的问题,但是如果您使用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);
}
}
公共类UnitOfWorkAttribute:ActionFilterAttribute
{
公共重写无效OnActionExecuting(HttpActionContext actionContext)
{
var context=IoC.CurrentNestedContainer.GetInstance();
context.BeginTransaction();
}
公共覆盖无效OnActionExecuted(HttpActionExecutedContext actionContext)
{
var context=IoC.CurrentNestedContainer.GetInstance();
CloseTransaction(actionContext.Exception);
}
}
我试图根据自己的经验来回答
1。什么时候我应该创建一个新的DbContext/我应该传递一个全局上下文吗?
上下文应该由依赖注入注入,而不应该由您自己实例化。最佳实践是通过依赖项注入将其创建为作用域服务。(见我对问题4的答复)
也请考虑使用一个适当的分层应用结构,如控制器>业务逻辑>知识库。在这种情况下,控制器接收的不是db上下文,而是存储库。在控制器中注入/实例化db上下文告诉我,您的应用程序体系结构在一个地方混合了许多责任,在任何情况下,我都不推荐这样做
2。我可以在所有地方重复使用一个全局上下文吗? 是的,你可以有,但问题应该是“应该我有…”->否。上下文用于每个请求更改存储库,然后再次删除 3。这会导致性能下降吗? 是的,这是因为DBContext并不是为全局而设计的。它存储所有输入或查询到的数据,直到数据被销毁。这意味着一个全局上下文将变得越来越大,对它的操作将变得越来越慢,直到出现内存不足异常,或者由于它的速度减慢到爬行状态而死亡 当多个线程同时访问同一上下文时,也会出现异常和许多错误 4。其他人是如何做到这一点的? 工厂通过依赖注入注入DBContext;范围:services.AddDbContext<UserDbContext>(o => o.UseSqlServer(this.settings.DatabaseOptions.UserDBConnectionString));
services.AddDbContext(o=>o.UseSqlServer(this.settings.DatabaseOptions.UserDBConnectionString));
我希望我的答案对您有所帮助。您应该在每次Save()操作后立即处理上下文。否则,每次后续保存将花费更长的时间。我有一个项目,在一个周期内创建和保存复杂的数据库实体。对m
services.AddDbContext<UserDbContext>(o => o.UseSqlServer(this.settings.DatabaseOptions.UserDBConnectionString));
using(var context=new DbContex())
{
var users=context.Users.Where(x=>x.ClassId==4).ToList();
}