In my experience, write your own repositories is redundant because EF implements this pattern already through DbSet's.
I worked with MVC3 + EF Code Fisrt in a recent project. We started implementing a generic repository following some tutorials and soon we realized that we are writing a lot of unnecessary and redundant code. Actually, the repositories were given us nothing but hiding a lot of the DbSet's functionality. Finally, we decided to remove them and work with our DbContext and DbSet's directly.
But, how about complex business logic beyond simple CRUD operations?
Well, we exposed all complex functionality like queries and multiple CRUD operations through a service layer. You can build different service classes by functionality. By example, you can write an AccountService to manage all functionality related with user accounts. Something like this:
public class AccountService {
private MyContext ctx;
public AccountService(DbContext dbContext) {
this.ctx = (MyContext)dbContext;
}
/// <summary>
/// Gets the underlying DbContext object.
/// </summary>
public DbContext DbContext {
get { return ctx; }
}
/// <summary>
/// Gets the users repository.
/// </summary>
public DbSet<User> Users {
get {return ctx.Users;}
}
public bool ValidateLogin(string username, string password) {
return ctx.Users.Any(u => u.Username == username && u.Password == password);
}
public string[] GetRolesForUser(string username) {
var qry = from u in ctx.Users
from r in u.Roles
where u.Username == username
select r.Code;
return qry.ToArray<String>();
}
public User CreateUser(string username, string password) {
if (String.IsNullOrWhiteSpace(username)) throw new ArgumentException("Invalid user name");
if (String.IsNullOrWhiteSpace(password)) throw new ArgumentException("Invalid password");
User u = new User {
Username = username.Trim().ToLower(),
Password = password.Trim().ToLower(),
Roles = new List<Role>()
};
ctx.Users.Add(u);
ctx.SaveChanges();
return u;
}
How about dependency injection?
Using this approach, the only thing we need to inject is the DbContext. The service classes has a constructor that takes a DbContext. So, when your controller constructor takes a service instance the DbContext will be injected to it.
Edit: Example code
This is an example code about how you controller could look:
public class HomeController : Controller {
private readonly AccountService accountService;
public AccountController(AccountService accountService) {
this.accountService = accountService;
}
}
And this could be the DI configuration using NInject:
private static void RegisterServices(IKernel kernel) {
kernel.Bind<MyContext>().ToSelf().InRequestScope();
kernel.Bind<DbContext>().ToMethod(ctx => ctx.Kernel.Get<MyContext>());
}
How about unit testing?
You could build specific interfaces for each service layer class and mock it where you need.