This article explains the repository pattern and will create a simple example to provide a basic idea of how the this pattern works.
To understand why we should use this pattern, let's use an example of an MVC application, using the Entity Framework. As long as we are getting the correct results, we are not concerned with how the application code is structured, what the various layers defined are, how they interact, how they pass the required data among them and so on and in most of the cases, we use the database context directly inside the controllers. This creates tight coupling between the controller and the data access layer and if we look closely into this type of code, it violates the Single Responsibility Principle as well as Open close principle. Any change related to the data-access layer can break the controller code. In such a case, our code structure has the following layers:
As seen from the preceding structure, layer 1 is using the database context directly and connects with the SQL Server. This is where the repository pattern can be implemented, to separate the layers. Our purpose will be to separate the controller and the data access layer (database context) using an intermediate layer, in other words repository layer, for communication between the two. So our code structure now changes to the following:
Example to use Repository pattern using C#
To implement this pattern, we can either use the approach of having a one-repository per model, which means, each entity of the database will have its own repository, or we can use a generic repository, that can be used by all the entities of the database.
For our example, we will be using the generic repository, with the database first approach along with Entity Framework 5.0 and .Net framework 4.0. So let's start with the example.
What a generic repository is
A generic repository is a generic class, with basic CRUD methods in it (and of course other methods can be added as needed). This class and its member functions can be used for any entity of the database. This means, if we have entities Customers and Orders, this single generic class can be used for both of them.
To start with, we will create a sample database with a table to store the Customer data. We will be creating a simple form in MVC to add the basic details in the table we created. Next, we will create a generic repository with our required operations to get all records, add/update/delete records. So our repository would look like the following.
Here, TEntity is the generic type that can be any entity of the database, in other words it could be Customer or it can be Orders. All the operations will be applied on this TEntity type only.
Next, our task will be to create a generic Unit Of Work class. If you are not familiar with Unit Of Work in the repository pattern, then I suggest you to read this previous article to get an idea of this. Just to re-iterate about Unit Of Work, it will act as the mediator between the MVC controller and the generic repository, to do all the database transactions in a single go (we will discuss that later in the article). This is because SaveChanges will be called by the instance of Unit Of Work class, only after it has done operations for the entities involved. So our generic Unit Of Work code will be like the following:
Here, we have a method named GetRepoInstance, that returns an instance of the type GenericRepository<TEntity>, where, TEntity represents the entity for which we will do the database operations. For example, if we are going to work with the Customer entity then it will return an instance of GenericRepository<Customer> and if we are going to work with the Order entity then it will return GenericRepository<Order>. Next we have the SaveChanges method to commit all the database transactions in one go, by the current instance of Unit Of Work we are using.
So we are done with setting up the Unit Of Work class. Now we move to the controller and will write the code to get/add/update/remove data. Let's start with the listing of the records. We will discuss the GetAllRecords repository method and on the same lines, the other methods will be called by the controller. To start with, we will create the Customer repository instance, using the Unit Of Work class. So we instantiate the Unit Of Work class and call the GetRepoInstance method to get the instance of the Customer repository. Now, when we call any method of the generic repository, it will call that method for the Customer entity, since it holds the reference to TEntity type at that time. This is because, when we initialize the generic repository, we created a DbSet of the type TEntity, in its constructor. So any type of CRUD operation is done on the DbSet. See the code below:
And, our controller method to fetch the records will look like the following:
That's it. We are done with the code to get the records. Run the application and see the results. Similarly, we can write the code for the other operations of update/add/delete. Just instantiate the Unit Of Work and get the instance for the entity repository. Call the methods and it's all we need to do. The rest of the code will look like the following:
Why Unit Of Work?
Earlier in our article, we explained a point about the preferred use of Unit Of Work class. The advantage of using this class is the fact that when we are doing multiple operations in one single controller method, we will be committing all the changes in the database by calling the SaveChanges only once and that is through the Unit Of Work instance.
For example, in our delete method above, we might also want to delete the Address related to that Customer(assuming it is in a separate table). In that case, we find the associated address record using the GetFirstOrDefault() method and call the delete operation for it.
Finally, we call the SaveChanges. In such a situation, if our first transaction fails, the other one will be also blocked, since the SaveChanges is never executed and thus maintains the database consistency.
So this was a basic article to get started with the repository pattern. I hope you enjoyed reading it!