Generic Repository Pattern with C# and Entity Framework✨
Hello everyone, I hope you are all doing well and in good health!
Today I wanted to write about Generic Repository and Unit Of Work Patterns. After the explanation part I will make a code example step by step to show how we can easily use and integrate it in our projects. so you can have an idea about how to use it.
What is Generic Repository and how to use it?
Generic repository pattern is on data layer to handle common data operations in a base repository so same operations will not be written again and again in the project. Let’s say we have product, product category and user tables on database and for all these database classes we will need to make the implementations. Like adding, deleting, updating and getting the data. In each entity class we will use these operations and instead of writing them again and again we can take them all in a base class so we will be able to use these operations without write them more the one time.
Let’s start to make an example about it. I have used Entity framework but you don’t have to use it just go on to read and try to understand because the matter is not what I used its about learning how to implement and why to use it.
To make the same example on your local you will need to;
Create an API or MVC project and add these 3 packages for Entity Framework integration.
- “Microsoft.EntityFrameworkCore”
- “Microsoft.EntityFrameworkCore.SqlServer”
- “Microsoft.EntityFrameworkCore.Tools”
Add these three packages to your projects so the example can work on your machine without getting any errors. Let’s go on.
I have created a Base entity and classes. Product, Category and order classes will be implementing BaseEntity class.
// It will be the generic type in generic repository class
public class BaseEntity
{
public int Id { get; set; }
}
public class Product : BaseEntity
{
public required string Name { get; set; }
public double Price { get; set; }
}
public class User : BaseEntity
{
public string FirstName { get; set; }
public string LastName { get; set; }
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
public string Password { get; set; }
}
public class Category : BaseEntity
{
public string Name { get; set; }
}
We have completed our entity classes now lets implement generic repository.
public interface IGenericRepository<T> where T : BaseEntity
{
public void Add(T entity);
public void Delete(T entity);
public void Update(T entity);
public List<T> GetAll();
public T GetById(int id);
}
I have added Generic repository interface here and some most common methods but methods may change as your needs so you don’t have to do the same. Basically you will add here the most common methods that you are using. Naming and methods depends on you and your project’s needs. The main point here is => “public interface IGenericRepository<T> where T : BaseEntity “ that. As you see it takes <T> as generic type and it says generic type should be implemented from BaseEntity class. So that’s why our product, category and user is can be send here as generic type because they are implementing BaseEntity.
Let’s complete the Implementation part which is GenericRepository class. And then we will be creating our repositories for our entities(product, category and user).
public class GenericRepository<T> : IGenericRepository<T> where T : BaseEntity
{
public readonly ApplicationDbContext _context;
public DbSet<T> entity => _context.Set<T>();
public GenericRepository(ApplicationDbContext context)
{
context = _context;
}
public void Add(T entity)
{
this.entity.Add(entity);
_context.SaveChanges();
}
public void Delete(T entity)
{
this.entity.Remove(entity);
_context.SaveChanges();
}
public List<T> GetAll()
{
return this.entity.ToList();
}
public T GetById(int id)
{
var entity = _context.Find<T>(id);
return entity;
}
public void Update(T entity)
{
_context.Update(entity);
_context.SaveChanges();
}
}
We have completed the implementation, as I say before I have used Entity framework but you don’t have to the only thing that will be change is the implementation.
So let’s go on and create repository interfaces and repository classes for product, category and user.
These are Repository interfaces:
public interface IProductRepoistory : IGenericRepository<Product>
{
//we can still add here product data opertaions but we dont neet to
//rewrite because we already add them with generic repository pattern
}
public interface ICategoryRepository : IGenericRepository<Category>
{
}
public interface IUserRepository : IGenericRepository<User>
{
}
As you see we gave the classes as type so when we use them it will know for which classes to make operations.
And Repository classes to implement interfaces:
public class ProductRepository : GenericRepository<Product>, IProductRepository
{
public ProductRepository(ApplicationDbContext context) : base(context)
{
}
//you can add here data operations for product.
}
public class CategoryRepository : GenericRepository<Category>, ICategoryRepository
{
public CategoryRepository(ApplicationDbContext context) : base(context)
{
}
}
public class UserRepository : GenericRepository<User>, IUserRepository
{
public UserRepository(ApplicationDbContext context) : base(context)
{
}
}
We have completed all need integration but just one small thing we have to do before we go on and add some data to database by using Generic Repository pattern.
You should add that code to the program.cs file the connection and creating objects for repository classes will be handled.
builder.Services.AddDbContext<ApplicationDbContext>(opt =>
opt.UseSqlServer("your connection string should be add here"));
builder.Services.AddScoped<IProductRepository, ProductRepository>();
builder.Services.AddScoped<ICategoryRepository, CategoryRepository>();
builder.Services.AddScoped<IUserRepository, UserRepository>();
Now we have completed the all configuration. Let’s create our database tables before we try to make any operations with them.
you should write these two command so Entity Framework will handle creating your database tables for you. Run them separately and get sure that your connection string is correct otherwise it won’t work.
add-migration Initial
update-database
Now our Generic repository pattern is ready to use it. We did not repeat ourselves to write the same operations again and again. We have created a base implementation and other repositories are able to use it by implementing it.
Let’s see how to use it;
public interface IProductService
{
void Add(Product product);
void Delete(Product product);
}
public class ProductService : IProductService
{
public readonly IProductRepository _productRepository;
public ProductService(IProductRepository productRepository)
{
_productRepository = productRepository;
}
public void Add(Product product)
{
_productRepository.Add(product);
}
public void Delete(Product product)
{
_productRepository.Delete(product);
}
}
I have created a service which is IProductService and added two methods for adding and deleting the data. And as you see I could call the product repository add and delete methods because its coming from Generic repository.
So that’s how we can add Generic Repository pattern to our projects. That was all I wanted to write about but if you want to add some data to see on database you can add the below code snippet to the program.cs file and run the project. I did not write all the methods so you can try to do that on your own and that will be a really good practice to understand it much better.
you should write it after var app = builder.Build(); method and you can check the repo from here.
using (var scope = app.Services.CreateScope())
{
var services = scope.ServiceProvider;
var productService = services.GetRequiredService<IProductService>();
// Now, you can use productService
Product product = new Product
{
Name = "Test",
Price = 10
};
productService.Add(product);
}
If you liked the article don’t forget to claps and follow on Medium, Happy Coding :)