我什么时候应该创建一个新的DbContext()

Jen*_*nsB 71 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()
        {

        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我在所有需要访问数据库的控制器的顶部使用以下行.我也在我的UserRepository类中使用它,它包含与用户相关的所有方法(例如获取活动用户,检查他拥有的角色等等):

ContextDB _db = new ContextDB();
Run Code Online (Sandbox Code Playgroud)

考虑到这一点......当一个访问者可以有多个DbContexts活动时,就会出现这种情况.如果他访问使用UserRepository的控制器..这可能不是最好的想法,我有一些关于它的问题

  1. 什么时候我应该创建一个新的DbContext /我应该有一个我传递的全局上下文?
  2. 我可以在所有地方重用一个全局上下文吗?
  3. 这是否会导致性能下降?
  4. 别人怎么做这个?

Ben*_*ale 76

我使用一个基本控制器来公开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);
    }
}
Run Code Online (Sandbox Code Playgroud)

我的应用程序中的所有控制器都源于BaseController并使用如下:

public class UserController : BaseController
{
    [HttpGet]
    public ActionResult Index()
    {
        return View(Database.Users.OrderBy(p => p.Name).ToList());
    }
}
Run Code Online (Sandbox Code Playgroud)

现在回答你的问题:

什么时候我应该创建一个新的DbContext /我应该有一个我传递的全局上下文?

应根据请求创建上下文.创建上下文,做你需要做的事情然后摆脱它.使用我使用的基类解决方案,您只需要担心使用上下文.

不要尝试拥有全局上下文(这不是Web应用程序的工作方式).

我可以在所有地方重用一个全局上下文吗?

不,如果你保留一个上下文,它将跟踪所有的更新,添加,删除等,这将减慢你的应用程序,甚至可能会导致一些非常微妙的错误出现在你的应用程序中.

您应该选择将您的存储库 Context 公开给您的控制器,但不能同时公开.如果两个上下文对应用程序的当前状态有不同的看法,那么从同一个方法访问两个上下文会导致错误.

就个人而言,我更喜欢DbContext直接公开,因为我看到的大多数存储库示例最终都是最终的薄包装器DbContext.

这是否会导致性能下降?

第一次DbContext创建a是非常昂贵的,但是一旦完成,就会缓存很多信息,以便后续的实例化更快.每次需要访问数据库时,您更容易看到保持上下文的性能问题而不是实例化.

别人怎么做这个?

这取决于.

有些人喜欢使用依赖注入框架在创建时将其上下文的具体实例传递给控制器​​.两种选择都很好.我更适合小规模的应用程序,你知道使用的特定数据库不会改变.

有些人可能会说你无法知道这一点,这就是为什么依赖注入方法更好,因为它使你的应用程序更容易适应变化.我对此的看法是它可能不会改变(SQL服务器和实体框架几乎不会模糊)并且我最好花时间编写特定于我的应用程序的代码.

  • 我没有什么可补充的,除了很高兴看到我自己的偏好反映在其他人的帖子中.我从来没有真正理解导致另一个层添加到DbContext上的存储库示例,而没有真正添加任何东西,我很喜欢创建一个公开受保护的DbContext的基类. (4认同)
  • 想要补充一点,这个答案很棒,但现在已经过时了EF6的发布,它会在每次使用后自动处理上下文.因此,有些情况下创建每个会话(全局)上下文是可以的.如果您使用EF6连接到存储过程并且数据锁定不是问题,那么在基本控制器中创建一次上下文并使所有需要数据库访问的控制器从基础继承可能是理想的.最正确的答案是您需要及时了解技术并为您的架构应用正确的模式. (4认同)

Rav*_*ior 6

我尝试根据自己的经验进行回答。

1.什么时候应该创建一个新的DbContext /应该传递一个全局上下文?

Context应该通过依赖项注入来注入,而不应该由您自己实例化。最佳实践是通过依赖项注入将其创建为范围服务。(请参阅我对问题4的回答)

也请考虑使用适当的分层应用程序结构,例如Controller> BusinessLogic> Repository。在这种情况下,控制器不是接收db-context,而是接收存储库。在控制器中注入/实例化数据库上下文告诉我,您的应用程序体系结构在一个地方混合了许多职责,在任何情况下,我都不建议这样做。

2.我可以在所有地方重复使用一个全局上下文吗?

是的,您可以拥有,但问题应该是“ 我应该拥有...”->否。应该根据每个请求使用上下文来更改存储库,然后再次将其删除。

3.这会导致性能下降吗?

是的,它这样做是因为DBContext根本不是为全局而设计的。它存储所有已输入或查询到的数据,直到销毁为止。这意味着全局上下文将变得越来越大,对其进行的操作将越来越慢,直到您遇到内存不足的异常或您死了,因为它们都慢下来了。

当多个线程一次访问同一上下文时,您还将获得异常和许多错误。

4.其他人怎么做?

通过工厂的依赖关系注入来注入DBContext;范围:

services.AddDbContext<UserDbContext>(o => o.UseSqlServer(this.settings.DatabaseOptions.UserDBConnectionString));
Run Code Online (Sandbox Code Playgroud)

希望我的回答对您有所帮助。