如何确定Dbcontexts的范围(防止整个应用程序的单例上下文)

Ale*_*lex 11 c# asp.net-mvc entity-framework

我想知道如何在实体框架中展示您的Dbcontexts,这样您就不会在整个应用程序中使用单个Dbcontext.我是Entity Framework的新手并且一直在阅读教程,但他们都使用单个Dbcontext作为示例,所以EF现在几乎是我的黑盒子.

比方说我有3个型号:

  • 岗位
  • 用户
  • 评论

每个模型彼此相关(帖子属于用户,评论属于用户和帖子).我是否为每个人单独制作一个Dbcontext?但这不正确,因为它们都是相关的,或者我会为我需要的每个场景制作Dbcontext?例如,如果我只需要查询Post和Comments而不是用户,那就是PostCommentsContext.然后我们会有一个PostUserCommentContext ...

RPM*_*984 7

最好的解决方案是使用工作单元来包装数据上下文,以及管理连接生命周期并允许您使用多个存储库(如果您倾向于沿着这条路走下去).

实施摘要:

  • 创建一个interface(IUnitOfWork),它公开你DbSet的属性,以及一个名为Commit的方法
  • 创建一个实现(EntityFrameworkUnitOfWork),根据需要实现.Commit只是在基类()上调用SaveChangesDbContext,并为最后一分钟逻辑提供了一个很好的挂钩.
  • 您的控制器接受a IUnitOfWork,使用DI(最好)解析a EntityFrameworkUnitOfWork,使用HTTP上下文作用域生存期设置(StructureMap对此有用)
  • (可选,但建议)创建一个Repository,它也可以IUnitOfWork通过Controller 获取并解决它.

HTH

编辑 - 回应评论

哦,你怎么能做涉及在多个模型中创建记录的工作呢?即,在同一事务中创建新用户和新帖子.

鉴于您使用ASP.NET MVC,您的控制器应该IUnitOfWork在其构造函数中接受.

这是一个例子,基于你的要求

public SomeController : Controller
{
   private IUnitOfWork _unitOfWork;
   private IUserRepo _userRepo;
   private IPostRepo _postRepo;

   public SomeController(IUnitOfWork unitOfWork, IUserRepo userRepo, IPostRepo postRepo)
   {
      _unitOfWork = unitOfWork; // use DI to resolve EntityFrameworkUnitOfWork
      _userRepo = userRepo;
      _postRepo = postRepo;
   }

   [HttpPost]
   public ActionResult CreateUserAndPost(User user, Post post)
   {
      // at this stage, a HTTP request has come in, been resolved to be this Controller
      // your DI container would then see this Controller needs a IUnitOfWork, as well
      // as two Repositories. DI smarts will resolve each dependency.
      // The end result is a single DataContext (wrapped by UoW) shared by all Repos.
      try
      {
         userRepo.Add(user);
         postRepo.Add(post);
         // nothing has been sent to DB yet, only two objects in EF graph set to EntityState.Added
         _unitOfWork.Commit(); // two INSERT's pushed to DB
      }
      catch (Exception exc)
      {
          ModelState.AddError("UhOh", exc.ToString());
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

还有一个问题,HTTP上下文作用生命周期是做什么的?

DI-talk中的对象具有范围管理设置,包括每个线程,每个会话,每个http请求,单例等.

HTTP-context scoped是Web应用程序的推荐设置.它意味着"在HTTP请求进入时新建上下文,并在请求完成时删除它".


Ste*_* K. 6

使用1个DbContext!这会让你的生活更轻松.不要担心性能,不会加载不需要或查询的数据,也不会消耗任何资源.

public class UserContext : DbContext
{
    public DbSet<User> Users { get; set; }
    public DbSet<Post> Posts { get; set; }
    public DbSet<Comment> Comments { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

对于某些情况,您可能需要2个或更多上下文.

像上面那样的上下文来保存应用程序工作所需的所有前端数据,以及另一个上下文 - 例如 - 存储从该前端数据生成的报告,并且仅用于后端你的申请.