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

}