Added Generics

This commit is contained in:
Charles Showalter 2022-05-10 15:45:47 -07:00
parent 7601a394b4
commit 8bca3f1f9d
9 changed files with 149 additions and 9 deletions

View File

@ -1,6 +1,7 @@
using Core.Entities;
using Microsoft.AspNetCore.Mvc;
using Core.Interfaces;
using Core.Specifications;
namespace API.Controllers
{
@ -8,36 +9,42 @@ namespace API.Controllers
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
private readonly iProductRepository _repo;
public ProductsController(iProductRepository repo)
private readonly IGenericRepository<Product> _productsRepo;
private readonly IGenericRepository<ProductBrand> _productBrandRepo;
private readonly IGenericRepository<ProductType> _productTypeRepo;
public ProductsController(IGenericRepository<Product> productsRepo, IGenericRepository<ProductBrand> productBrandRepo, IGenericRepository<ProductType> productTypeRepo)
{
_repo = repo;
_productTypeRepo = productTypeRepo;
_productBrandRepo = productBrandRepo;
_productsRepo = productsRepo;
}
[HttpGet]
public async Task<ActionResult<List<Product>>> GetProducts()
{
var products = await _repo.GetProductsAync();
var spec = new ProductsWithTypesAndBrandsSpecification();
var products = await _productsRepo.ListAsync(spec);
return Ok(products);
}
[HttpGet("{id}")]
public async Task<ActionResult<Product>> GetProduct(int id)
{
return await _repo.GetProductByIdAsync(id);
var spec = new ProductsWithTypesAndBrandsSpecification(id);
return await _productsRepo.GetEntityWithSpec(spec);
}
[HttpGet("brands")]
public async Task<ActionResult<IReadOnlyList<ProductBrand>>> GetProductBrands()
{
return Ok(await _repo.GetProductBrandsAsync());
return Ok(await _productBrandRepo.ListAllAsync());
}
[HttpGet("types")]
public async Task<ActionResult<IReadOnlyList<ProductType>>> GetProductTypes()
{
return Ok(await _repo.GetProductTypesAsync());
return Ok(await _productTypeRepo.ListAllAsync());
}
}

View File

@ -1,3 +1,4 @@
using Infrastructure;
using Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
@ -16,7 +17,7 @@ namespace API
{
var context = services.GetRequiredService<StoreContext>();
await context.Database.MigrateAsync();
await Infrastructure.StoreContextSeed.SeedAsync(context, loggerFactory);
await StoreContextSeed.SeedAsync(context, loggerFactory);
}
catch (Exception ex)
{

View File

@ -21,6 +21,7 @@ namespace API
services.AddControllers();
services.AddDbContext<StoreContext>(x => x.UseSqlite(_config.GetConnectionString("DefaultConnection")));
services.AddScoped<iProductRepository, ProductRepository>();
services.AddScoped(typeof(IGenericRepository<>), (typeof(GenericRepository<>)));
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "WebAPIv5", Version = "v1" });

View File

@ -0,0 +1,13 @@
using Core.Entities;
using Core.Specifications;
namespace Core.Interfaces
{
public interface IGenericRepository<T> where T : BaseEntity
{
Task<T> GetByIdAsync(int id);
Task<IReadOnlyList<T>> ListAllAsync();
Task<T> GetEntityWithSpec(ISpecification<T> spec);
Task<IReadOnlyList<T>> ListAsync(ISpecification<T> spec);
}
}

View File

@ -0,0 +1,23 @@
using System.Linq.Expressions;
namespace Core.Specifications
{
public class BaseSpecification<T> : ISpecification<T>
{
public BaseSpecification()
{
}
public BaseSpecification(Expression<Func<T, bool>> criteria)
{
Criteria = criteria;
}
public Expression<Func<T, bool>> Criteria { get; }
public List<Expression<Func<T, object>>> Includes { get; } =
new List<Expression<Func<T, object>>>();
protected void AddInclude(Expression<Func<T, object>> includeExpression)
{
Includes.Add(includeExpression);
}
}
}

View File

@ -0,0 +1,11 @@
using System.Linq.Expressions;
namespace Core.Specifications
{
public interface ISpecification<T>
{
Expression<Func<T, bool>> Criteria {get; }
List<Expression<Func<T, object>>> Includes {get; }
}
}

View File

@ -0,0 +1,20 @@
using System.Linq.Expressions;
using Core.Entities;
namespace Core.Specifications
{
public class ProductsWithTypesAndBrandsSpecification : BaseSpecification<Product>
{
public ProductsWithTypesAndBrandsSpecification()
{
AddInclude(x => x.ProductType);
AddInclude(x => x.ProductBrand);
}
public ProductsWithTypesAndBrandsSpecification(int id) : base(x => x.Id == id)
{
AddInclude(x => x.ProductType);
AddInclude(x => x.ProductBrand);
}
}
}

View File

@ -0,0 +1,41 @@
using Core.Entities;
using Core.Interfaces;
using Core.Specifications;
using Microsoft.EntityFrameworkCore;
namespace Infrastructure.Data
{
public class GenericRepository<T> : IGenericRepository<T> where T : BaseEntity
{
private readonly StoreContext _context;
public GenericRepository(StoreContext context)
{
_context = context;
}
public async Task<T> GetByIdAsync(int id)
{
return await _context.Set<T>().FindAsync(id);
}
public async Task<IReadOnlyList<T>> ListAllAsync()
{
return await _context.Set<T>().ToListAsync();
}
public async Task<T> GetEntityWithSpec(ISpecification<T> spec)
{
return await ApplySpecification(spec).FirstOrDefaultAsync();
}
public async Task<IReadOnlyList<T>> ListAsync(ISpecification<T> spec)
{
return await ApplySpecification(spec).ToListAsync();
}
private IQueryable<T> ApplySpecification(ISpecification<T> spec)
{
return SpecificationEvaluator<T>.GetQuery(_context.Set<T>().AsQueryable(), spec);
}
}
}

View File

@ -0,0 +1,23 @@
using Core.Entities;
using Core.Specifications;
using Microsoft.EntityFrameworkCore;
namespace Infrastructure.Data
{
public class SpecificationEvaluator<TEntity> where TEntity : BaseEntity
{
public static IQueryable<TEntity> GetQuery(IQueryable<TEntity> inputQuery, ISpecification<TEntity> spec)
{
var query = inputQuery;
if (spec.Criteria != null)
{
query = query.Where(spec.Criteria);
}
query = spec.Includes.Aggregate(query, (current, include) => current.Include(include));
return query;
}
}
}