In the first two posts I handled UI things, how to organize your areas (controller-services) and I showed a possibility to create your business-logic regarding area-Services and business-services. In this post I want to show you (like in thousand other blogs before ;) ) the Unit-Of-Work-Pattern in use with generic repositories (repository-pattern). This makes the trilogy of the architecture posts complete (for this time. Maybe there will be others in the future ;) )
First things first: What is the repository-pattern? Well, if you built up your application the right way you should have several objects which should be persisted in the database. This can be Users, Projects, or whatever your applications wants to deal with.
For each of these objects you need the normal CRUD-operations. And when you implemented these operations the second and third time, at the latest, you can see that these methods are always the same. Adding an object, getting a single object, getting all objects, updating an object and deleting an object. Period. This is basically all you need.
If you need more operations, or you have to deal with many of these mentioned above sequential you can build a service for this. Read part I and II for handling this ;)
So these operations are always the same. So it would be nice if we could do like a class, with an interface, which offers us there operations, no matter which type we are going to use.
And exactly this is what this generic repositories are for.
But what is the Unit-Of-Work (UoW) and why another Unit-Of-Work-Abstraction?
If you already dealed with the Entity-Framework (EF) you have used the UoW-Pattern all the time. The repository-pattern, too. And so you have already seen how it works: The UoW is tracking all your changes, gathering them together to get every information and changes on the database you need and sending them altogether into the database when you have finished your request. Like the DatabaseContext does. So the UoW with the repositories represents an abstraction of your database and it “reminds” all your changes.
Note: “Projects” is a normal DTO which is used for dealing with the Entity Framework. Could look like this
You should have a normal DatabaseContext with all your entities on it and your model-creating-stuff using the FluentAPI.
Nothing new until here. I am always hiding things in namespaces, so in my root-folder I am creating a “Repositories”-Folder which is hiding all my Repo-stuff.
Let’s go into this in detail:
For offering the same operations on every entity we have we need something like a base-class (with interface) which offers us everything we can do with an object (CRUD with a little bit more. Let’s call it CRUD+ ;) ).
Note: I just looked into the web and found a good solution for this generic-things
So I combined them and just put in a little effort then.
This is the RepositoryBase. With its interface IRepositoryBase.
So here right in the beginning we see the heart of the thing we want to take a look at with this blogpost.
In this generic repository we are able to perform every operation we want with an object, while being able to include some child-properties, to find all, to find a single entry (with the find-method which will eventually not force a direct query), to get a single entry with a query etc.
But let’s put this interface into a more flexible context. I added, like shown in the links above, a repository-provider which is caching the repositories and creating them with a factory (factory-pattern).
So the factory is creating all the repositories you want to have including caching them. While creating it checks the cache first and if not available it creates a new one (RepositoryProviderImpl).
I will go into this later, but while looking into this code: Not every Repository has to follow the CRUD-Things in the repository-base like shown above. You can also build up extended repositories and custom ones you complete implemented on your own way.
So at this point you have implemented the repository for each entity and you are able to give these things to the outside world through your provider who creates the repositories as implemented.
Now you need a UnitOfWork to use in your application to access these repositories and use them. This could look like this:
Notice the IDisposable-Interface which the implementation of the UoW is implementing. This is why you can use it with a “using” in the end.
The GetGenericRepository() can be used if you would like to have standard CRUD-Functions on your entity. This should be the case in like 80% of your use-cases.
The GetCustomRepository() can give you back the custom repository which you have implemented because you want to have like other functions or for any other reason. You just have to implement its interface and offer it through the UoW-Interface.
You can also do extended interfaces, if you want to extend the CRUD-Methods because they are not enough.
Just let the repository-interface inherit from your repositorybase-interface and the class from the repositorybase-implementation. Because the methods are virtual you can override them or just add new functions.
You can provide it again with the normal UoW-Interface:
Now you have a generic repository which you can user for every entity. Its extendable with very few steps and you are also free if you want to use own repositories.
Wrapped in namespaces this it how it could look to you:
You can use it now from the outside with
And you are done :)
If you want to add new repositories you just have to extend your UoW-interface and add your new entities to your databaseContext.
If you are using Ninject to inject your stuff and for IoC you can simply make your UnitOfWork present in the NinjectWebCommon.cs as InRequestScope. So it is injected once per request and you can Use DI
I hope I could give you a view into the UoW-Thing with generic repositories. But, like I said in the beginning, I only gathered information and put them together in one scope. And, of course, this is only one of soooo many articles in the web concerning UnitOfWork and Generic-Repos.
But I hope you liked reading it ;)
This is the last part of the architecture-posts in ASP.NET MVC. This was planned as a trilogy and here it is.