I was wondering how do you scope out your Dbcontexts in Entity Framework so you don't use a single Dbcontext for your entire application. I am new to Entity Framework and have been reading tutorials, but they all used a single Dbcontext as an example, so EF is pretty much a blackbox for me right now.
Let's say for example I have 3 models:
Each model is related to each other (A Post belongs to User, Comment belongs to User and Post). Do I make a Dbcontext for each one individually? But that wouldn't be correct since they are all related, or would I make a Dbcontext for each scenario that I need? For example, if I only need to query for Post and Comments and not user, that would be a PostCommentsContext. And then we would have a PostUserCommentContext...
The best solution would be to use a Unit of Work to wrap the Data Context, as well as managing the connection lifetime and allowing you to work with multiple Repositories (if you were so inclined to go down that path).
Summary of implementation:
IUnitOfWork
) which exposes properties for your DbSet
's, as well as a single method called Commit
EntityFrameworkUnitOfWork
), implementing as required. Commit simply calls SaveChanges on the base class (DbContext
), and also provides a good hook-in for last minute logic.IUnitOfWork
, use DI (preferably) to resolve a EntityFrameworkUnitOfWork
, with a HTTP-context scoped lifetime setting (StructureMap is good for this)IUnitOfWork
, and work off that via your Controller.HTH
EDIT - In Response to Comments
Oh, how can you do work that involves creating records in multiple models then? i.e., create a new user and a new post in the same transaction.
Given your using ASP.NET MVC, your controllers should accept an IUnitOfWork
in their constructor.
Here's an example, based on what you asked
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());
}
}
}
And one more question, what does the HTTP-context scoped lifetime do?
Objects in DI-talk have scope management settings that include per thread, per session, per http request, singleton, etc.
HTTP-context scoped is the recommended setting for web apps. It means "new up a context when a HTTP request comes in, and get rid of it when the request is finished".
Use 1 DbContext! That will make life easier for you. Don't worry about performance, data that isn't needed or queried won't be loaded and won't consume any resources.
public class UserContext : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<Post> Posts { get; set; }
public DbSet<Comment> Comments { get; set; }
}
For some scenarios you might want 2 or more contexts.
A context like the one above to hold all the front-end data needed for your application to work and another context for - as an example - to store reports generated from that front-end data, and which is only used in the back-end of you application.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With