Full-stack application development with AngularJS 11 and Asp.Net MVC Core 5.0 — Generic Repositories and Contollers[part4/4]

Creating a Repository Pattern

dotnet ef migrations add ReplacingId
dotnet ef database update
namespace ServerApp.Data
{
public interface IEntity
{
long Id { get; set; }
}
}
using System.Collections.Generic;
using System.Threading.Tasks;
namespace ServerApp.Data
{
public interface IRepository<T> where T : class, IEntity
{
Task<List<T>> GetAll();
Task<T> Get(long id);
Task<T> Add(T entity);
Task<T> Update(T entity);
Task<T> Delete(long id);
}
}
using ServerApp.Models;namespace ServerApp.Data.EFCore
{
public abstract class Repository<TEntity, TContext> :
IRepository<TEntity>
where TEntity : class, IEntity
where TContext : DataContext
{
}
}
using Microsoft.EntityFrameworkCore;
using ServerApp.Models;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace ServerApp.Data.EFCore
{
public abstract class Repository<TEntity, TContext> :
IRepository<TEntity>
where TEntity : class, IEntity
where TContext : DataContext
{
private readonly TContext context;
public Repository(TContext context)
{
this.context = context;
}
public async Task<TEntity> Add(TEntity entity)
{
context.Set<TEntity>().Add(entity);
await context.SaveChangesAsync();
return entity;
}
public async Task<TEntity> Delete(long id)
{
var entity = await context.Set<TEntity>().FindAsync(id);
if (entity == null)
{
return entity;
}
context.Set<TEntity>().Remove(entity);
await context.SaveChangesAsync();
return entity;
}
public async Task<TEntity> Get(long id)
{
return await context.Set<TEntity>().FindAsync(id);
}
public async Task<List<TEntity>> GetAll()
{
return await context.Set<TEntity>().ToListAsync();
}
public async Task<TEntity> Update(TEntity entity)
{
context.Entry(entity).State = EntityState.Modified;
await context.SaveChangesAsync();
return entity;
}
}
}
using ServerApp.Models;namespace ServerApp.Data.EFCore
{
public class ProductRepository : Repository<Product, DataContext>
{
DataContext _context;
public ProductRepository(DataContext context) : base(context)
{
_context = context;
}
}
}
using ServerApp.Models;namespace ServerApp.Data.EFCore
{
public class SupplierRepository : Repository<Supplier, DataContext>
{
DataContext _context;
public SupplierRepository(DataContext context) : base(context)
{
_context = context;
}
}
}
using ServerApp.Models;namespace ServerApp.Data.EFCore
{
public class RatingRepository : Repository<Rating, DataContext>
{
DataContext _context;
public RatingRepository(DataContext context) : base(context)
{
_context = context;
}
}
}
services.AddScoped<ProductRepository>();
services.AddScoped<SupplierRepository>();
services.AddScoped<RatingRepository>();

Creating Generic Controller Classes

using Microsoft.AspNetCore.Mvc;
using ServerApp.Data;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace ServerApp.Controllers
{
[Route("api/[controller]")]
[ApiController]
public abstract class AppController<TEntity, TRepository> : ControllerBase
where TEntity : class, IEntity
where TRepository : IRepository<TEntity>
{
private readonly TRepository repository;
public AppController(TRepository repository)
{
this.repository = repository;
}
// GET: api/[controller][HttpGet]
public async Task<ActionResult<IEnumerable<TEntity>>> Get()
{
return await repository.GetAll();
}
// GET: api/[controller]/5
[HttpGet("{id}")]
public async Task<ActionResult<TEntity>> Get(long id)
{
var entity = await repository.Get(id);
if (entity == null)
{
return NotFound();
}
return entity;
}
// PUT: api/[controller]/5
[HttpPut("{id}")]
public async Task<IActionResult> Put(long id, TEntity entity)
{
if (id != entity.Id)
{
return BadRequest();
}
await repository.Update(entity);
return NoContent();
}
// POST: api/[controller]
[HttpPost]
public async Task<ActionResult<TEntity>> Post(TEntity entity)
{
await repository.Add(entity);
return CreatedAtAction("Get", new { id = entity.Id }, entity);
}
// DELETE: api/[controller]/5
[HttpDelete("{id}")]
public async Task<ActionResult<TEntity>> Delete(long id)
{
var entity = await repository.Delete(id);
if (entity == null)
{
return NotFound();
}
return entity;
}
}
}
using Microsoft.AspNetCore.Mvc;
using ServerApp.Data.EFCore;
using ServerApp.Models;
namespace ServerApp.Controllers
{
[Route("api/products")]
[ApiController]
public class ProductValuesController : AppController<Product, ProductRepository>
{
ProductRepository _repository;
public ProductValuesController(ProductRepository repository) : base(repository)
{
_repository = repository;
}
}
}
using Microsoft.AspNetCore.Mvc;
using ServerApp.Data.EFCore;
using ServerApp.Models;
namespace ServerApp.Controllers
{
[Route("api/suppliers")]
[ApiController]
public class SupplierValuesController : AppController<Supplier, SupplierRepository>
{
SupplierRepository _repository;
public SupplierValuesController(SupplierRepository repository) : base(repository)
{
_repository = repository;
}
}
}
https://localhost:5001/api/products
https://localhost:5001/api/suppliers

Applying filtering in the Web Service

public async Task<List<Product>> GetWithRelated(string category, string search, bool related = false)
{
IQueryable<Product> query = _context.Products;
if (!string.IsNullOrWhiteSpace(category))
{
string catLower = category.ToLower();
query = query.Where(p => p.Category.ToLower().Contains(catLower));
}
if (!string.IsNullOrWhiteSpace(search))
{
string searchLower = search.ToLower();
query = query.Where(p => p.Name.ToLower().Contains(searchLower)
|| p.Description.ToLower().Contains(searchLower));
}
if (related)
{
query = query.Include(p => p.Supplier).Include(p => p.Ratings);
List<Product> data = await query.ToListAsync();
data.ForEach(p =>
{
if (p.Supplier != null)
{
p.Supplier.Products = null;
}
if (p.Ratings != null)
{
p.Ratings.ForEach(r => r.Product = null);
}
});
return data;
}
else
{
return await query.ToListAsync();
}
}
[HttpGet("rel")]
public async Task<ActionResult<IEnumerable<Product>>> GetProducts(string category, string search, bool related = false)
{
return await _repository.GetWithRelated(category, search, related);
}
https://localhost:5001/api/products/rel?category=sports
https://localhost:5001/api/products/rel?category=sports&related=true
https://localhost:5001/api/products/rel?related=true
https://localhost:5001/api/products/

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store