π Step 2: Implementing a Generic Repository (Introducing Category Repository)
π‘ Goal:
In this article, we will refactor our Product Repository by implementing a Generic Repository Pattern. Additionally, we will introduce the Category Repository, demonstrating how the Generic Repository improves code reusability and maintainability.
π Updated Project Structure (With Generic Repository)
π ProductApp βββ π Core # Domain Layer β βββ π Entities β β βββ BaseEntity.cs β β βββ Product.cs β β βββ Category.cs β βββ π Interfaces β β βββ IRepository.cs # Generic Repository Interface β β βββ IProductRepository.cs β β βββ ICategoryRepository.cs β βββ π Infrastructure # Data Access Layer β βββ π Data β β βββ Repository.cs # Generic Repository Implementation β β βββ ProductRepository.cs β β βββ CategoryRepository.cs β β βββ StoreContext.cs β βββ π API # Presentation Layer β βββ π Controllers β β βββ ProductsController.cs β β βββ CategoriesController.cs β βββ π DTOs β β βββ ProductDto.cs β β βββ CategoryDto.cs
1οΈβ£ Define the Base Entity
π Core/Entities/BaseEntity.cs
namespace Core.Entities { public abstract class BaseEntity { public int Id { get; set; } } }
2οΈβ£ Define the Generic Repository Interface
π Core/Interfaces/IRepository.cs
using System.Collections.Generic; using System.Threading.Tasks; namespace Core.Interfaces { public interface IRepository<T> where T : BaseEntity { Task<T?> GetByIdAsync(int id); Task<List<T>> ListAllAsync(); void Add(T entity); void Update(T entity); void Remove(T entity); Task<bool> SaveAllAsync(); } }
3οΈβ£ Implement the Generic Repository
π Infrastructure/Data/Repository.cs
using System.Collections.Generic; using System.Threading.Tasks; using Core.Entities; using Core.Interfaces; using Microsoft.EntityFrameworkCore; namespace Infrastructure.Data { public class Repository<T> : IRepository<T> where T : BaseEntity { private readonly StoreContext _context; private readonly DbSet<T> _dbSet; public Repository(StoreContext context) { _context = context; _dbSet = _context.Set<T>(); } public async Task<T?> GetByIdAsync(int id) { return await _dbSet.FindAsync(id); } public async Task<List<T>> ListAllAsync() { return await _dbSet.ToListAsync(); } public void Add(T entity) { _dbSet.Add(entity); } public void Update(T entity) { _dbSet.Update(entity); } public void Remove(T entity) { _dbSet.Remove(entity); } public async Task<bool> SaveAllAsync() { return await _context.SaveChangesAsync() > 0; } } }
4οΈβ£ Define the **Category
**** Entity**
π Core/Entities/Category.cs
namespace Core.Entities { public class Category : BaseEntity { public string Name { get; set; } = string.Empty; } }
5οΈβ£ Implement the **ICategoryRepository
**** Interface**
π Core/Interfaces/ICategoryRepository.cs
using Core.Entities; namespace Core.Interfaces { public interface ICategoryRepository : IRepository<Category> { } }
6οΈβ£ Implement the **CategoryRepository
**
π Infrastructure/Data/CategoryRepository.cs
using Core.Entities; using Core.Interfaces; namespace Infrastructure.Data { public class CategoryRepository : Repository<Category>, ICategoryRepository { public CategoryRepository(StoreContext context) : base(context) { } } }
7οΈβ£ Register the Repositories in **Program.cs
**
π API/Program.cs
using Infrastructure.Data; using Microsoft.EntityFrameworkCore; var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); // Register StoreContext with Dependency Injection builder.Services.AddDbContext<StoreContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"))); // Register Repositories builder.Services.AddScoped(typeof(IRepository<>), typeof(Repository<>)); builder.Services.AddScoped<IProductRepository, ProductRepository>(); builder.Services.AddScoped<ICategoryRepository, CategoryRepository>(); var app = builder.Build(); // Apply Migrations Automatically (Optional: Good for development) using var scope = app.Services.CreateScope(); var services = scope.ServiceProvider; var context = services.GetRequiredService<StoreContext>(); context.Database.Migrate(); app.UseSwagger(); app.UseSwaggerUI(); app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run();
8οΈβ£ Create and Apply Migrations
Run the following commands in the API project folder:
# Create a Migration dPM> dotnet ef migrations add AddCategoryEntity No project was found. Change the current working directory or use the --project option. # Apply the Migration to Update the Database dotnet ef database update
π Step 2 is Complete
β We refactored the Product Repository using a Generic Repository.\
β We introduced the Category Repository, demonstrating reusability.\
β The Generic Repository now enables easy expansion for future entities.\
β We added and applied migrations to update the database.
π Whatβs Next?
In the next article, we will introduce the Specification Pattern to handle complex queries efficiently. This will allow filtering, sorting, and pagination without cluttering our repositories.
Stay tuned! π
Top comments (0)