I'm working on a quite large application. The domain has about 20-30 types, implemented as ORM classes (for example EF Code First or XPO, doesn't matter for the question). I've read several articles and suggestions about a generic implementation of the repository pattern and combining it with the unit of work pattern, resulting a code something like this:
public interface IRepository<T> {
IQueryable<T> AsQueryable();
IEnumerable<T> GetAll(Expression<Func<T, bool>> filter);
T GetByID(int id);
T Create();
void Save(T);
void Delete(T);
}
public interface IMyUnitOfWork : IDisposable {
void CommitChanges();
void DropChanges();
IRepository<Product> Products { get; }
IRepository<Customer> Customers { get; }
}
Is this pattern suitable for really large applications? Every example has about 2, maximum 3 repositories in the unit of work. As far as I understood the pattern, at the end of the day the number of repository references (lazy initialized in the implementation) equal (or nearly equal) to the number of domain entity classes, so that one can use the unit of work for complex business logic implementation. So for example let's extend the above code like this:
public interface IMyUnitOfWork : IDisposable {
...
IRepository<Customer> Customers { get; }
IRepository<Product> Products { get; }
IRepository<Orders> Orders { get; }
IRepository<ProductCategory> ProductCategories { get; }
IRepository<Tag> Tags { get; }
IRepository<CustomerStatistics> CustomerStatistics { get; }
IRepository<User> Users { get; }
IRepository<UserGroup> UserGroups { get; }
IRepository<Event> Events { get; }
...
}
How many repositories cab be referenced until one thinks about code smell? Or is it totally normal for this pattern? I could probably separate this interface into 2 or 3 different interfaces all implementing IUnitOfWork, but then the usage would be less comfortable.
UPDATE
I've checked a basically nice solution here recommended by @qujck. My problem with the dynamic repository registration and "dictionary based" approach is that I would like to enjoy the direct references to my repositories, because some of the repositories will have special behaviour. So when I write my business code I would like to be able to use it like this for example:
using (var uow = new MyUnitOfWork()) {
var allowedUsers = uow.Users.GetUsersInRolw("myRole");
// ... or
var clothes = uow.Products.GetInCategories("scarf", "hat", "trousers");
}
So here I'm benefiting that I have a strongly typed IRepository and IRepository reference, hence I can use the special methods (implemented as extension methods or by inheriting from the base interface). If I use a dynamic repository registration and retrieval method, I think I'm gonna loose this, or at least have to do some ugly castings all the time.
For the matter of DI, I would try to inject a repository factory to my real unit of work, so it can lazily instantiate the repositories.