visit
public interface IRepository<TEntity> where TEntity : class
{
TEntity Get(int id);
IEnumerable<TEntity> GetAll();
IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate);
void Add(TEntity entity);
void AddRange(IEnumerable<TEntity> entities);
void Remove(TEntity entity);
void RemoveRange(IEnumerable<TEntity> entities);
}
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
private readonly DbContext _context;
private readonly DbSet<TEntity> _dbSet;
public Repository(DbContext context)
{
_context = context;
_dbSet = context.Set<TEntity>();
}
public TEntity Get(int id)
{
return _dbSet.Find(id);
}
public IEnumerable<TEntity> GetAll()
{
return _dbSet.ToList();
}
public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
{
return _dbSet.Where(predicate);
}
public void Add(TEntity entity)
{
_dbSet.Add(entity);
}
public void AddRange(IEnumerable<TEntity> entities)
{
_dbSet.AddRange(entities);
}
public void Remove(TEntity entity)
{
_dbSet.Remove(entity);
}
public void RemoveRange(IEnumerable<TEntity> entities)
{
_dbSet.RemoveRange(entities);
}
}
static void Main(string[] args)
{
using (var context = new MyDbContext())
{
var repository = new Repository<Customer>(context);
var customer = new Customer { Name = "John Doe", Email = "[email protected]" };
repository.Add(customer);
var customers = repository.GetAll();
foreach (var c in customers)
{
Console.WriteLine(c.Name);
}
}
}
public interface IRepository<T> where T : class
{
IEnumerable<T> GetAll();
T GetById(int id);
void Add(T entity);
void Update(T entity);
void Delete(T entity);
}
public class Repository<T> : IRepository<T> where T : class
{
private readonly DbContext _context;
private readonly DbSet<T> _entities;
public Repository(DbContext context)
{
_context = context;
_entities = context.Set<T>();
}
public IEnumerable<T> GetAll()
{
return _entities.ToList();
}
public T GetById(int id)
{
return _entities.Find(id);
}
public void Add(T entity)
{
_entities.Add(entity);
_context.SaveChanges();
}
public void Update(T entity)
{
_context.Entry(entity).State = EntityState.Modified;
_context.SaveChanges();
}
public void Delete(T entity)
{
_entities.Remove(entity);
_context.SaveChanges();
}
}
In the above example, we have established an interface IRepository and a practical implementation Repository pattern to distinguish the data access logic from the business logic.
public class ProductService
{
private readonly IRepository<Product> _repository;
public ProductService(IRepository<Product> repository)
{
_repository = repository;
}
public IEnumerable<Product> GetAllProducts()
{
return _repository.GetAll();
}
public Product GetProductById(int id)
{
return _repository.GetById(id);
}
public void AddProduct(Product product)
{
_repository.Add(product);
}
public void UpdateProduct(Product product)
{
_repository.Update(product);
}
public void DeleteProduct(Product product)
{
_repository.Delete(product);
}
}
To test the ProductService
class, we need to implement a mock repository object that implements the IRepository<Product>
interface. Please find below the code example for the same.
[TestClass]
public class ProductServiceTests
{
[TestMethod]
public void GetAllProducts_Returns_All_Products()
{
// Arrange
var products = new List<Product>
{
new Product { Id = 1, Name = "Product 1", Price = 10.0m },
new Product { Id = 2, Name = "Product 2", Price = 20.0m },
new Product { Id = 3, Name = "Product 3", Price = 30.0m }
};
var mockRepository = new Mock<IRepository<Product>>();
mockRepository.Setup(r => r.GetAll()).Returns(products.AsQueryable());
var productService = new ProductService(mockRepository.Object);
// Act
var result = productService.GetAllProducts();
// Assert
CollectionAssert.AreEqual(products, result.ToList());
}
// Other unit tests for the ProductService class...
}
To manage these typical CRUD operations, we can develop the generic repository interface IRepository<TEntity>
and the generic repository implementation Repository<TEntity>
.
Now, let's create specific repository interfaces and implementations for both Customer
and Order
entities:
public interface ICustomerRepository : IRepository<Customer>
{
Customer GetCustomerById(int id);
}
public class CustomerRepository : Repository<Customer>, ICustomerRepository
{
public CustomerRepository(DbContext dbContext) : base(dbContext)
{
}
public Customer GetCustomerById(int id)
{
return GetById(id);
}
}
public interface IOrderRepository : IRepository<Order>
{
IQueryable<Order> GetOrdersByCustomer(int customerId);
}
public class OrderRepository : Repository<Order>, IOrderRepository
{
public OrderRepository(DbContext dbContext) : base(dbContext)
{
}
public IQueryable<Order> GetOrdersByCustomer(int customerId)
{
return GetAll().Where(o => o.CustomerId == customerId);
}
}
By reusing the Repository<TEntity>
class for both the CustomerRepository
and OrderRepository
classes, we are inheriting from the IRepository<TEntity>
Interface to provide common CRUD operations.
Also published