Struggling with repository pattern
Repository and unit of work
The known repository pattern combined with a unit of work pattern are a great idea if you have to abstract your persistence layer away. I saw more than one implementation so far. Some I would use as well and some I’m happy I don’t have to maintain.
Repository implementations
Currently I work on a project that builds up some reusable framework to support some often used customer needs in our business. Some data are managed by this framework, that also provides a standard UI (asp.net mvc) for administration. These information have to be stored to a database. We do not want to couple the whole framework to entity framework because looking to the future, we see a lot more than that. CosomosDB is coming and we do want to support EF 6, EF core, mongodb and possibly some more. So looking back to some previous experience I see the repository and unit of work approach as a solution among others. And to be clear, it is not a one size fits all solution. These kind of solutions simply do not exist.
base scenario
For simplicity I reduce the code to the essential and provide only a example.
public class EntityA {
[Required]
public Guid Id { get; set }
[Required]
public string Name { get; set; }
public virtual ICollection<DetailA> Details { get; set; }
}
public class DetailA {
[Required]
public Guid Id { get; set }
[Required]
public string Name { get; set; }
[Required]
public EntityA Parent { get; set; }
}
public interface IRepository<T> {
T GetById(Guid id);
IColleciton<T> GetAll();
void Update(T entity);
void Insert(T entity);
}
public interface IEntityARepository : IRepository<EntityA> {
}
public interface IUnitOfWork {
TRepo GetRepository<TRepo>();
void SaveChanges();
}
The definition of Martin Fowler
A short quote of Martin Fowler’s definition of a repository take from his official page
A Repository mediates between the domain and data mapping layers, acting like an in-memory domain object collection.
So given this definition the following code will be completely valid.
using(var uow = Resolver.Resolve<IUnitOfWork>()) {
var repository = uow.GetRepository<IEntityARepository>();
var entity repository.GetById(id)
entity.Name = "NewName;
uow.SaveChanges();
}
- You can not cache the entities, because they are context bound
- In disconnected scenarios (like webapps) you have to load the entities for all actions again.
- It simply does not work out of the box with e.g. mongodb driver
The pragmatic solution
The pragmatic version looks similar to this:
using(var uow = Resolver.Resolve<IUnitOfWork>()) {
var repository = uow.GetRepository<IEntityARepository>();
var entity repository.GetById(id)
entity.Name = "NewName;
repository.Update(entity);
uow.SaveChanges();
}
Hint: Do validate these update calls with unit tests so that they can’t get lost.
What entities do deserve a repository?
This question is tricky. The answer to this question has direct impact of the number of repositories you have to build or how bloated your repository interface will become.
every entity gets a repository
The easy way is to say that every entity gets an own repository. Looking at the example above we would also have a repository for DetailA. Does this make sense? Probably yes and probably no. If you follow the rule strictly, DetailA does get a repository. But does it make sense? In this case it wouldn’t make sense because DetailA can not exist without EntityA. An what about the hidden entities that are used to build n:m relations? Should they be implemented as a class and have it’s own repository even if they have only the two ids as fields? I’d say no, they shouldn’t. So in my opinion this is not a good rule to build your repositories.
only aggregate roots get a repository
Another approach is to use the aggregate roots to build repositories. So every aggregate root entity gets a repository implementation. This may sound easy and logical but it isn’t. In the example above there will only be the EntityARepository and no DetailA repository. Simple because DetailA depends on EntityA and can not stand for it’s own. This is an easy example and everyone may follow here. But what about the following situation?
public class User {
[Required]
public Guid Id { get; set }
[Required]
public string Name { get; set; }
public virtual ICollection<Role> Roles { get; set; }
}
public class Role {
[Required]
public Guid Id { get; set }
[Required]
public string Name { get; set; }
public virtual ICollection<User> Users { get; set; }
}
Should I use this pattern?
As always, it depends :-) If you just have a tiny little application that is not supposed to grow or live long, I would not use this pattern. If it is a quick and dirty prototype, I would not use it either. It would be a overkill and the chance that you change your database background is quite low. So use your db and implement the code within the application service classes.
We currently use it in a library used to support building asp.net mvc apps with a often used set of basic functionality of our customers. In this case we think it is worth the effort to implement this pattern. Just because we let the app developer decide where the data is stored. Some like to have it in a sql database, some in cosmosdb and some in a local mongodb. So we have implemented EF6 support and are planning to provide mongodb as well. But it is nut sure if we keep the repository pattern for the next major version.
The future?
After implementing the repository pattern once more and fighting once more these topics and potential issues with the mapping, I think I’m not going to implement it in the next solution, library or project. I think I’m going to use a implementation of the CQRS-Pattern. This does not mean I’m going to use event sourcing. CQRS with event sourcing is a whole different story ;-) But luckily we can use CQRS without event sourcing.