I\'m gonna to use repository and UnitOfwork in my data access layer to do this take a look at one contact aggregateroot
public interface IAggregateRoot
{
I agree with the Doctor, DbContext is already a UnitOfWork, and adding another UoW abstraction on top of it is typically redundant, unless you think it's highly likely you might switch database technologies in the future.
I don't agree, however, with treating DbSet's as repositories, since this tightly couples your queries to the methods that use them. If you need to change a query, you have to do it everywhere you use it.
I prefer to either use a stand-alone repository (or service interface, they serve similar functions) or to use more of a CQRS system for Command/Query Seperation, an use query objects.
It's not a direct answer to your question, but it might simplify things a little bit and reduce duplication.
When you use e.g. EntityFramework Power Tools to reverse-engineer Code First (or just use Code First in general), you end up with the DbContext
class that serves as a UoW and repository in one, e.g.:
public partial class YourDbContext : DbContext
{
public DbSet<Contact> Contacts {get; set;}
}
Now, if you want things to be testable, there's an easy way: introduce a very thin interface:
public interface IDbContext
{
IDbSet<T> EntitySet<T>() where T : class;
int SaveChanges();
//you can reveal more methods from the original DbContext, like `GetValidationErrors` method or whatever you really need.
}
then make another file with second part of the partial class:
public partial class YourDbContext : IDbContext
{
public IDbSet<T> EntitySet<T>() where T : class
{
return Set<T>();
}
}
Ta-da! Now you can inject IDbContext
with YourDbContext
backing it up:
//context is an injected IDbContext:
var contact = context.EntitySet<Contact>().Single(x => x.Id == 2);
contact.Name = "Updated name";
context.EntitySet<Contact>().Add(new Contact { Name = "Brand new" });
context.SaveChanges();
Now if you want to have control over the disposal of the context, then you'd have to write your own (gasp) IDbContextFactory
(generic or not, depending what you need) and inject that factory instead.
No need to write your own Find
, Add
or Update
methods now, DbContext
will handle that appropriately, it's easier to introduce explicit transactions and everything is nicely hidden behind interfaces (IDbContext
, IDbSet
).
By the way, the IDbContextFactory
would be an equivalent to NHibernate's ISessionFactory
and IDbContext
- ISession
. I wish EF had this out of the box, too.
Inside the UnitOfWork class you need to implement DBContext or ObjectContext.
UnitOfWork segregates all transactions regardless of the system. EF is only for DB connection. Even if your system is only using DB still it is better to keep a separate UnitOfWork class for future expansions.
And inside the unit of work Commit(), you can call the internally implemented DBContext.SaveChanges().
This DBcontext will be accessible to all repositories declared inside unitofwork. So repositories add or delete from DBcontext and unitOfwork commits it.
When you have scenarios spanning different storages eg: Cloud Blobs, table storage etc. You could implement them inside UnitofWork just like you implemented a EF context. And some repositories can access Table Storage and some EF context.
Tip: Implementing ObjectContext instead of DBContext gives you an edge in caching scenarios. And you have more options in extending your framework.