Download as pdf or txt
Download as pdf or txt
You are on page 1of 6

What is Generic Repository Design Pattern in C#?

The Generic Repository pattern in C# is a design pattern that abstracts


the application’s data layer, making it easier to manage data access logic
across different data sources. It aims to reduce redundancy by
implementing common data operations in a single, generic repository
rather than having separate repositories for each entity type.

Key Concepts
● Generic Interface: A generic repository typically starts with a
generic interface defining common operations like Add, Delete,
Find, and Update. These operations are defined in a generic way,
applicable to any entity type.
● Implementation: The generic interface is then implemented in a
concrete class. This class handles the data source interactions, such
as querying a database using an ORM (like Entity Framework).
● Entity Framework Context: The implementation will often
utilize an Entity Framework context to interact with the database.

When to Use Generic Repository Pattern in C#?


Here are some situations where using the Generic Repository Pattern is
beneficial:

● CRUD Operations: If your application performs standard Create,


Read, Update, and Delete (CRUD) operations and these operations
are largely the same across different entities or data models, a
generic repository can reduce repetitive code.
● Decoupling: When you want to decouple the business logic of
your application from the data access layer, a generic repository
can act as a middle layer, making it easier to modify or replace
your data access logic without impacting the rest of your
application.
● Testing and Mocking: In unit testing, mock data access logic is
often necessary. A generic repository can simplify this process
because you only need to mock a single, generic repository rather
than individual repositories for each entity.
● Code Reusability: If your application handles multiple entities
that share similar data access patterns, using a generic repository
can promote code reusability and reduce the need for redundant
code.
● Maintainability: A generic repository can make the codebase
cleaner and more maintainable, especially in large applications
where managing individual repositories for each entity can become
cumbersome.
● Simple Data Models: For applications with simple data models
and straightforward data access requirements, a generic repository
provides a quick and easy way to implement data access without
overcomplicating the architecture.

However, it’s also important to recognize scenarios where the Generic


Repository Pattern might not be the best choice:

● Complex Queries: If your application requires complex queries,


the generic repository can become a limitation, as it might not be
able to handle specific query needs efficiently.
● Over-Abstraction: Sometimes, the abstraction provided by the
generic repository can hide important details of the data access
layer, making it harder to optimize or handle specific data access
scenarios.
● Performance Concerns: A generic repository might introduce
unnecessary overhead for performance-critical applications,
especially if the pattern leads to inefficient database access.
Example Code =>
public interface IRepository<T> where T : class
{
void Add(T entity);// Add Data Store
void Update(T entity);// Update Data Store in Table
void Remove(T entity);// Remove in which Store Date
void Remove(int Id);// Unique Id using Data Store Delete
void RemoveRange(IEnumerable<T> values);//Multiple Record Data Delete

T Get(int Id);
IEnumerable<T> GetAll(Expression<Func<T,bool>> Filter=null,
Func<IQueryable<T>,IOrderedQueryable<T>> orderBy=null,
string includeProperties=null);// Category,CoverType,Product included in the result set.

T FirstOrDefault(
Expression<Func<T, bool>> Filter = null,
string includeProperties=null);

}
Implementing IGenericRepository Interface
public class Repository<T>:IRepository<T> where T : class
{
private readonly ApplicationDbContext _context;
internal DbSet<T> dbSet;
public Repository(ApplicationDbContext context)
{
_context = context;
dbSet = _context.Set<T>();
}

public void Add(T entity)


{
dbSet.Add(entity);
}
public T FirstOrDefault(Expression<Func<T, bool>> Filter = null,
string includeProperties = null)
{
IQueryable<T> query = dbSet;
if(Filter != null)
query = query.Where(Filter);
if(includeProperties != null)
{
foreach (var includePrope in includeProperties.Split(new[] {','},
StringSplitOptions.RemoveEmptyEntries))
{
query=query.Include(includePrope);
}
}
return query.FirstOrDefault();
}

public T Get(int Id)


{
return dbSet.Find(Id);
}

public IEnumerable<T> GetAll(Expression<Func<T, bool>> Filter = null,


Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null,
string includeProperties = null)
{
throw new NotImplementedException();
}

public void Remove(T entity)


{
dbSet.Remove(entity);
}

public void Remove(int Id)


{
dbSet.Remove(Get(Id));
}
public void RemoveRange(IEnumerable<T> values)
{
dbSet.RemoveRange(values);
}

public void Update(T entity)


{
_context.ChangeTracker.Clear();
dbSet.Update(entity);
}

Repositories: Repositories are responsible for the CRUD (Create, Read,


Update, Delete) operations for specific entities. They encapsulate the
data access logic.

Unit of Work: The Unit of Work is a higher-level abstraction that


coordinates the work done through repositories. It is responsible for
managing transactions and ensuring that changes to multiple entities are
committed or rolled back as a single unit.

Code=>
public interface IUnitOfWork
{
public ICategoryRepository Category { get; }
public ICoverTypeRepository CoverType { get; }
public ISP_Call SP_Call { get; }
public IProductRepository Product { get; }
public ICompanyRepository Company { get; }
public IApplicationUserRepository ApplicationUser { get; }
public IShoppingCartRepository ShoppingCart { get; }
public IOrderHeaderRepository OrderHeader { get; }
public IOrderDetailRepository OrderDetail { get; }

void Save();
}
public class UnitOfWork : IUnitOfWork
{
private readonly ApplicationDbContext _context;
public UnitOfWork(ApplicationDbContext context)
{
_context = context;
Category=new CategoryRepository(context);
CoverType = new CoverTypeRepository(context);
SP_Call = new SP_Call(context);
Product= new ProductRepository(context);
ApplicationUser= new ApplicationUserRepository(context);
Company= new CompanyRepository(context);
ShoppingCart = new ShoppingCartRepository(context);
OrderHeader = new OrderHeaderRepository(context);
OrderDetail = new OrderDetailRepository(context);
}

public ICategoryRepository Category { private set; get; }


public ICoverTypeRepository CoverType { private set; get; }
public ISP_Call SP_Call { private set; get; }
public IProductRepository Product { private set; get; }
public IApplicationUserRepository ApplicationUser { private set; get; }
public ICompanyRepository Company { private set; get; }
public IShoppingCartRepository ShoppingCart { private set; get; }
public IOrderHeaderRepository OrderHeader { private set; get; }
public IOrderDetailRepository OrderDetail { private set; get; }
public void Save()
{
_context.SaveChanges();
}
}

You might also like