Reputation: 5398
Getting deeper with entity framework and repositories in order to enable better testing. Wondering if this is wise though?
public interface IRepository
{
int SaveChanges();
void Dispose();
}
using (MyContext context = new MyContext())
{
TransactionRepository txns = new TransactionRepository(context); // TransactionRepository implement IRepository
MappingRepository maps = new MappingRepository(context); // MappingRepositoryimplement IRepository
SomeCommand command = new SomeCommand(txns, maps);
command.Execute();
}
Each of the repositories is logically different, so in theory could be in different data sources. For now, they use the same database though. Each of the repository classes implements IRepository, and notably SaveChanges() along with some query methods that I've not shown for brevity.
What's a good practice for utilize multiple repositories?
Upvotes: 3
Views: 4040
Reputation: 101140
The most important thing is forgotten: The database connection is not shared between multiple DbContext
instances. That means that you have to use distributed transactions if you would like several repositories to be in the same transaction. That's a large performance degrade compared to a local transactions.
Upvotes: 4
Reputation: 11328
+1 gorilla, some goods points made. I would add the following thoughts.
In web/mvc scenario , I use dozens of repositories and inject the Context into these Repositories. I use a repository base class. I also UoW classes which use a context in constructor. The Unit Of Work Classes contains references to all supported repositories for the context. I also use bounded contexts. Here is a sample blogs from Julie Lerman on the subject. http://www.goodreads.com/author/show/1892325.Julia_Lerman/blog
So yes, it makes perfect sense to use multiple contexts and to use multiple repositories. You may even have multiple Unit of Work classes, although concurrent use of UoW classes is another discussion.
ADDING SAMPLE code as requested: This sample is one of Several LuW classes that inherits from a base LuW class. The current state and DBContext to be use is injected. (or defaulted) The repositories are interfaces from CORE project. The LuW classes are in the DAL project.
the base LuW is something like....
public interface ILuw : ILuwEvent, IDisposable
{
IBosCurrentState CurrentState{ get; set; }
OperationStatus Commit();
}
The Luw Class itself.
namespace XYZ.DAL
{
public class LuwBosMaster : Luw, ILuwBosMaster
{
public LuwBosMaster(DbContext context, IBosCurrentState currentState)
{
base.Initialise(context,currentState);
}
public LuwBosMaster()
{
base.Initialise(GetDefaultContext(), BosGlobal.BGA.IBosCurrentState);
}
public static DbContextBosMaster GetDefaultContext()
{
return new DbContextBosMaster("BosMaster");
}
//MasterUser with own Repository Class
private IRepositoryMasterUser _repositoryMasterUser;
public IRepositoryMasterUser RepMasterUser
{ get { return _repositoryMasterUser ?? (_repositoryMasterUser = new RepositoryMasterUser(Context, CurrentState)); } }
//20 other repositories declared adn available within this Luw
// Some repositories might address several tables other single tables only.
// The repositories are based on a base class that common generic behavior for each MODEL object
Im sure you get the basic idea...
Upvotes: 6
Reputation: 19842
This really comes down to design decisions on your part. If you're following Unit Of Work pattern, then each repository is probably going to have it's own context; mainly because according to UoW, each repository call should create it's context, do it's work, and then dispose of it's context.
There are other good reasons to share a context though, one of which (IMHO) is that the context has to track the state of an entity, if you're get an entity, dispose the context, make some modifications to the entity, and then attach to a new context this new context has to go hit the database so it can figure out the state of the entity. Likewise if you're working with graphs of entities (Invoices, and all their InvoiceItems), then the new context would have to fetch all the entities in the graph to determine their state.
Now, if you're working with web pages or services where you are not or cannot maintain a state, then the UoW pattern is sort of implied and it's a generally accepted "good practice".
Upvotes: 4