Repository Pattern in c#
Published: 2024-03-08 10:35:56

Any good software must be guided by design patterns. Design patterns are nothing more, nothing less than a set of best practices and mechanisms to make the code more robust, organized, and easy to maintain.

There are different design patterns for different situations and today, we will focus on one of the most commonly used patterns: the Repository Pattern.

The Repository Pattern is a design pattern commonly used in software development, particularly in applications that interact with databases or other data sources. It provides an abstraction layer between the application's business logic and the data access logic.

In essence, the Repository Pattern involves creating an interface or class (the repository) that defines methods for accessing data, such as querying, adding, updating, and deleting records. This repository acts as a mediator between the application's code and the data storage mechanism, abstracting away the details of how data is retrieved and manipulated.

With a repository pattern and the abstraction it provides, it's very simple, for example, to switch databases in an application. Let's imagine that we want to switch from a SQL Server database to MongoDB. All that will be needed is to implement a new repository implementation to apply the logic to MongoDB.

I'll present here a simple example of implementing a repository for a customer API. This API will have the following methods: GetAll, GetById, and Add.

The first thing to do is to create an interface that will define the repository contract. In this case, the interface will require the implementation of the `GetAll`, `GetById`, and `Add` methods.

```
public interface ICustomerRepository
    {
        Task<Customer> GetById(int id);
        Task<List<Customer>> GetAll();
        Task<Customer> Add(Customer customer);
    }
```

And our Customer model is a simple class with the following fields:

```
 [Table("customer")]
    public class Customer
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        [Column("customer_id")]
        public int CustomerId { get; set; }
        [Column("customer_name")]
        public string CustomerName { get; set; }
        [Column("mobile_no")]
        public string MobileNumber { get; set; }
        [Column("email")]
        public string Email { get; set; }
    }
```

With the interface created, the next step is to implement these methods in a class called `CustomerRepository`, which will implement the previously created interface `ICustomerRepository`.

```
public class CustomerRepository : ICustomerRepository
    {
        private readonly CustomerDbContext _customerDbContext;

        public CustomerRepository(CustomerDbContext customerDbContext)
        {
            _customerDbContext = customerDbContext;
        }

        public async Task<Customer> Add(Customer customer)
        {

            var result = _customerDbContext.Customers.Add(customer);
            await _customerDbContext.SaveChangesAsync();
            return result.Entity;    
        }

        public async Task<Customer> GetById(int id)
        {
            return await _customerDbContext.Customers.FirstOrDefaultAsync(a => a.CustomerId == id);
        }

        public async Task<List<Customer>> GetAll()
        {
            return await _customerDbContext.Customers.ToListAsync();
        }
    }
```
In this application, I'm using a local SQL Server database to store information, but let's keep the example simple and leave the database for another example.

Now, what we need to do is create the controller for our API, which will call our repository. This controller will receive the repository via dependency injection, allowing it to access all the methods implemented earlier.

```
[Route("api/[controller]")]
    [ApiController]
    public class CustomerController : ControllerBase
    {
        private readonly ICustomerRepository _customerRepository;
        public CustomerController(ICustomerRepository customerRepository)
        {
            _customerRepository = customerRepository;
        }

        [HttpGet]
        [Route("getAll")]
        public ActionResult<IEnumerable<Customer>> GetCustomers()
        {
            return _customerRepository.GetAll().Result;
        }

        [HttpGet]
        [Route("{id}")]
        public ActionResult<Customer> GetCustomers(int id)
        {
            return _customerRepository.GetById(id).Result;
        }

        [HttpPost]
        [Route("add")]
        public ActionResult<Customer> Create([FromBody]Customer customer)
        {
            var newCustomer =   _customerRepository.Add(customer).Result;
            return Ok(newCustomer);
        }
    }
```

As you can see in the controller, we receive the repository via dependency injection and assign it in the constructor. Then, in each of the REST methods, we access the repository through the "_customerRepository".

The last thing to do is register our repository implementation in the C# dependency container. To do this, in the `Program.cs`, we'll register our implementation.

```
builder.Services.AddScoped<ICustomerRepository, CustomerRepository>();
```

You can find this example in my github repository:
[Github](https://github.com/iamlobito/MicroServicesSolution)