I have set up my generic repository as follows:
public interface IRepository<T> : IDisposable where T : Entity
{
T GetById(int id);
}
public abstract class Repository<T> : IRepository<T> where T : Entity
{
protected readonly SqlDbContext _context = new SqlDbContext();
public T GetById(int id)
{
return _context.Set<T>().Find(id);
}
}
To enable dependency injection in my MVC app i also create a Product interface since the signature differs. This is also the case for the other repositories.
public interface IProductRepository : IRepository<Product>
{
IEnumerable<Product> GetDiscountedProducts();
}
And the implementation (note the inheritance)
public class ProductRepository : Repository<Product>, IProductRepository
{
public IEnumerable<Product> GetDiscountedProducts()
{
return _context.Set<Product>().Where(x=>x)...
}
}
Finally the repository gets injected into the MVC controller using unity
public HomeController(IProductRepository repository)
{
}
Is it just me or is this inheritance chain a bit messy here? Is there any way to improve this design?
To implement generic repository pattern, create two projects - one is an ASP.NET Core Web Application and another is a class library project, which are GR. Web and GR. Data respectively in the solution. The class library is named as SA.
You have to register the dependencies in IServiceCollection in startup class. ASP.NET Core supports the constructor Injections to resolve the injected dependencies. Here, register the interface and their implementation into DI, using the add method of different lifetimes.
They really aren't comparable a repository is something you can inject via dependency injection. The aim of DI is to make your application loosely coupled. Rather than specify a concrete implementation you can specify an interface that defines a contract that an implementation must fulfil.
I would suggest to avoid IProductRepository
for this particular case (when simply adding single and very specific method) and enhance original IRepository interface as shown below:
public interface IRepository<TEntity> : IDisposable
where TEntity : Entity
{
TEntity GetById(int id);
IEnumerable<TEntity> List(IFilterCriteria criteria);
}
and then implement
public sealed class ProductDiscountFilterCriteria : IFilterCriteria
{
// ...
}
but in such case you've to define some logic to transform criteria to an query, it could be a LINQ Expression as you'are already using LINQ. If such creteria expression approach is complex for your case - I would suggest to stick with approach you've proposed.
EDIT: IFilterCriteria
is simply Query Object pattern implementation
interface IFilterCriteria<TQuery>
{
TQuery ToQuery();
}
public sealed class ProductDiscountFilterCriteria : IFilterCriteria<DynamicExpression>
{
public decimal Discount { get; private set; }
public DynamicExpression ToQuery()
{
// build expression for LINQ clause Where("Discount" > this.Discount)
}
}
OR raw SQL criteria builder:
public sealed class ProductDiscountFilterCriteria : IFilterCriteria<string>
{
public decimal Discount { get; private set; }
public string ToQuery()
{
// simplified
return "WHERE Discount < " + this.Discount;
}
}
So then you would be able to use it like:
var products = productRepository.List<Product>(
new DiscountFilterCriteria { Discount = 50 });
Dynamic LINQ examples and articles:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With