Repository Pattern in MVC

Alifiyakapasi
5 min readSep 5, 2024

--

A design pattern for controlling data access in software applications is the repository pattern. Applications that follow the Model-View-Controller (MVC) architecture structure are especially subject to it.

What is the Repository Pattern?

Data access logic can be abstracted and encapsulated using the Repository Pattern. It serves as a mediator between your application’s business logic and the data source, which could be a database, an API, or another type of storage. The main goal is to detach data access from business logic by offering a clear interface.

Key Components:

  1. Repository Interface: Repository Interface: Specifies how the data can be accessed. Typically, it has functions like Update, Add, and Remove..
  2. Implementation of the Repository: This part handles the real data access logic and offers a concrete implementation of the methods specified in the interface.
  3. Data Source: The real data supplier or storage (like a database).

The Repository Pattern’s Advantages :

  1. Separation of Concerns: You can draw separate boundaries between these concerns by dividing data access logic from business logic. As a result, the codebase is easier to maintain and more modular.
  2. Testability: During unit testing, it’s simpler to simulate or dummy repositories. This lets you test your logic for business logic separate from the data access layer.
  3. Flexibility: Only the repository implementation, not the business logic, needs to change when the data source is changed (for example, from a SQL database to a NoSQL database).
  4. Consistency: Gives users a standardized method for organizing and retrieving data across the various program sections.
  5. Decoupling: Makes it easier to change or replace the data access logic without affecting other components of the application by facilitating in the decoupling of the data access layer from the rest of the application.

Why Use Repository Pattern in MVC?

In the context of MVC (Model-View-Controller), the Repository Pattern is often used to:

  1. Encapsulate Data Access: In the MVC paradigm, views display the data, models describe the data, and controllers manage user input. Instead of going straight to the data source, controllers use repositories to interact with the data via a well-defined interface. This maintains the models’ and controllers’ attention on their tasks and cleanliness.
  2. Promote Code Reusability: You can repurpose the same data access functionality across several application components by utilizing repositories. For instance, distinct controllers can consistently access the same data by using the same repository.
  3. Boost Maintainability: When data access is managed by a repository, modifications to the data source or access logic solely impact the repository. This makes maintenance easier and lowers the chance of new bugs coming in because the rest of the application is not impacted.
  4. Boost Testability: Controllers and business logic can be tested more quickly and separately without requiring a real data source by using repositories that are simple to mock or stub in unit tests.

Here, we’ll put the repository pattern into practice using the service class library and repository:

First, make two class libraries for the repository and service.Yes, Click Solution, then choose New Project.

Hereafter, choose….

Next, click, and provide whatever you wish.

Names are often provided as solutionName.Services

Next, select the.NET Framework, then click “Create.”

Subsequently, you must provide each other with references in order to establish connections.

Here, DEMO.Services and DEMO.Repository are created.

Thus, make reference to Services in the Demo and to the Repository in the Service. Demo -> Services -> Repository

  • The most important thing to keep in mind is to be careful not to develop a circular dependency.
  • When two or more components are dependent on one another, it can be challenging to break the loop because each component is necessary for the other to work correctly. This is known as a circular dependency.

How to give references:

Select the DEMO.Services Project by right-clicking on the DEMO Project, then choose Add ⇒ Project Reference and click OK.

Add a reference for DEMO.Repository and do the same for DEMO.Services.

I’ll give an example of a repository and service for an earlier project here.

Click here to read that story.

UserController.cs

public class UserController : Controller
{
private readonly IUserService _userService;

public UserController(IUserService userService)
{
_userService = userService;
}

// GET: User
public async Task<ActionResult> Index()
{
var models = await _userService.GetAllUsersAsync();
return View(models);
}

// GET: User/Create
public ActionResult Create()
{
return View();
}

// POST: User/Create
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create(UserModel model)
{
if (ModelState.IsValid)
{
await _userService.CreateUserAsync(model);
return RedirectToAction("Index");
}
return View(model);
}

// GET: User/Edit/id
public async Task<ActionResult> Edit(string id)
{
var model = await _userService.GetUserByIdAsync(id);
return View(model);
}

// POST: User/Edit/id
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit(string id, UserModel model)
{
if (ModelState.IsValid)
{
await _userService.UpdateUserAsync(id, model);
return RedirectToAction("Index");
}
return View(model);
}

// GET: User/Delete/id
public async Task<ActionResult> Delete(string id)
{
await _userService.DeleteUserAsync(id);
return RedirectToAction("Index");
}
}

UserService.cs

public class UserService : IUserService
{
private readonly IUserRepository _userRepository;

public UserService(IUserRepository userRepository)
{
_userRepository = userRepository;
}

public async Task<List<UserModel>> GetAllUsersAsync()
{
return await _userRepository.GetAllActiveUsersAsync();
}

public async Task<UserModel> GetUserByIdAsync(string id)
{
return await _userRepository.GetUserByIdAsync(id);
}

public async Task CreateUserAsync(UserModel model)
{
if (model == null)
throw new ArgumentNullException(nameof(model));

await _userRepository.AddUserAsync(model);
}

public async Task UpdateUserAsync(string id, UserModel model)
{
if (model == null)
throw new ArgumentNullException(nameof(model));

await _userRepository.UpdateUserAsync(id, model);
}

public async Task DeleteUserAsync(string id)
{
await _userRepository.DeleteUserAsync(id);
}
}

IUserService.cs

public interface IUserService
{
Task<List<UserModel>> GetAllUsersAsync();
Task<UserModel> GetUserByIdAsync(string id);
Task CreateUserAsync(UserModel model);
Task UpdateUserAsync(string id, UserModel model);
Task DeleteUserAsync(string id);
}

UserRepository.cs

public class UserRepository : IUserRepository
{
private readonly IMongoCollection<UserModel> _collection;

public UserRepository(MongoDBContext context)
{
_collection = context.UserCollection;
}

public async Task<List<UserModel>> GetAllActiveUsersAsync()
{
return await _collection.Find(x => !x.IsDeleted).ToListAsync();
}

public async Task<UserModel> GetUserByIdAsync(string id)
{
return await _collection.Find(x => x.Id == id).FirstOrDefaultAsync();
}

public async Task AddUserAsync(UserModel model)
{
await _collection.InsertOneAsync(model);
}

public async Task UpdateUserAsync(string id, UserModel model)
{
await _collection.ReplaceOneAsync(x => x.Id == id, model);
}

public async Task DeleteUserAsync(string id)
{
// Ideally, you would handle the soft delete here
var update = Builders<UserModel>.Update.Set(x => x.IsDeleted, true);
await _collection.UpdateOneAsync(x => x.Id == id, update);
}
}

IUserRepository.cs

public interface IUserRepository
{
Task<List<UserModel>> GetAllActiveUsersAsync();
Task<UserModel> GetUserByIdAsync(string id);
Task AddUserAsync(UserModel model);
Task UpdateUserAsync(string id, UserModel model);
Task DeleteUserAsync(string id);
}

In Program.cs

// Register repositories and services
builder.Services.AddScoped<IUserRepository, UserRepository>();
builder.Services.AddScoped<IUserService, UserService>();

Structure of Project

Happy Coding!!!

--

--

No responses yet