我想知道如何在实体框架中扩展您的Dbcontexts,这样您就不会在整个应用程序中使用单个Dbcontext。我是Entity Framework的新手并且一直在阅读教程,但他们都使用单个Dbcontext作为示例,所以EF现在几乎是我的黑盒子。
比方说,我有3个型号:
每个模型彼此相关(帖子属于用户,评论属于用户和帖子)。我是否为每个人单独制作一个Dbcontext?但这不正确,因为它们都是相关的,或者我会为我需要的每个场景制作Dbcontext?例如,如果我只需要查询Post和Comments而不是用户,那就是PostCommentsContext。然后我们会有一个PostUserCommentContext ...
最好的解决方案是使用a 工作单位 包装数据上下文,以及管理连接生命周期并允许您使用多个存储库(如果您倾向于沿着这条路径前进)。
实施摘要:
- 创建一个界面(
IUnitOfWork
)暴露你的属性 DbSet
的,以及一个叫做的方法 承诺
- 创建一个实现(
EntityFrameworkUnitOfWork
),按要求实施。提交只是打电话 保存更改 在基类(DbContext
),并为最后一分钟的逻辑提供了一个很好的挂钩。
- 你的控制器接受了
IUnitOfWork
,使用DI(最好)解决一个问题 EntityFrameworkUnitOfWork
,用 HTTP上下文作用域生存期 设置 (StructureMap 对此有好处)
- (可选,但建议)创建一个 知识库 这也需要
IUnitOfWork
,并通过您的控制器解决这个问题。
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());
}
}
}
还有一个问题,HTTP上下文范围的生命周期是做什么的?
DI-talk中的对象具有范围管理设置,包括每个线程,每个会话,每个http请求,单例等。
HTTP-context scoped是Web应用程序的推荐设置。它意味着“在HTTP请求进入时新建上下文,并在请求完成时删除它”。
使用1个DbContext!这将使你的生活更轻松。不要担心性能,不会加载不需要或查询的数据,也不会消耗任何资源。
public class UserContext : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<Post> Posts { get; set; }
public DbSet<Comment> Comments { get; set; }
}
对于某些情况,您可能需要2个或更多上下文。
像上面那样的上下文来保存应用程序工作所需的所有前端数据,以及另一个上下文 - 例如 - 存储从该前端数据生成的报告,并且仅用于后端你的申请。
我正在试验UnitofWork,这是我想出来的......
首先,我创建了一个只包含一个方法的IUnitofWork。 Commit();
然后我的dbContext看起来像这样
public class myContext : DbContext, IUnitOfWork
{
public DbSet<Users> Users { get; set; }
public DbSet<Addresses> Address { get; set; }
public void Save()
{
SaveChanges();
}
}
我的存储库类在他们的ctors中使用UnitofWork。
public class UserRepository : IRepository<Position>
{
private myContext _context;
public UserRepository (IUnitOfWork unitOfWork)
{
if (unitOfWork == null)
throw new ArgumentNullException("unitOfWork");
_context = unitOfWork as myContext;
}
/// other methods ///
}
那么控制器中的代码就是这样的
_unitOfWork = new myContext();
_userDB = new UserRepository(_unitOfWork);
_addressDB = new AddressRepository(_unitOfWork);
_userDB.Add(newUser);
_addresesDB.Add(newAddress);
_unitOfWork.Save();
我已经调试并证明在调用_unitOfWork的Save方法之前不会提交任何数据。很酷的东西!!