Merge branch 'master' of https://labs.xtechnology.org/cshowalter/E-Commerce
This commit is contained in:
commit
263aa50631
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,4 +1,4 @@
|
|||||||
obj
|
obj
|
||||||
bin
|
bin
|
||||||
appsettings.json
|
appsettings.json
|
||||||
*.db
|
*.db*
|
@ -6,6 +6,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="11.0.0" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.4" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.4" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.4">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.4">
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
using Core.Entities;
|
using Core.Entities;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Core.Interfaces;
|
using Core.Interfaces;
|
||||||
|
using Core.Specifications;
|
||||||
|
using API.Dtos;
|
||||||
|
using AutoMapper;
|
||||||
|
|
||||||
namespace API.Controllers
|
namespace API.Controllers
|
||||||
{
|
{
|
||||||
@ -8,24 +11,46 @@ namespace API.Controllers
|
|||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
public class ProductsController : ControllerBase
|
public class ProductsController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly iProductRepository _repo;
|
private readonly IGenericRepository<Product> _productsRepo;
|
||||||
public ProductsController(iProductRepository repo)
|
private readonly IGenericRepository<ProductBrand> _productBrandRepo;
|
||||||
|
private readonly IGenericRepository<ProductType> _productTypeRepo;
|
||||||
|
private readonly IMapper _mapper;
|
||||||
|
public ProductsController(IGenericRepository<Product> productsRepo, IGenericRepository<ProductBrand> productBrandRepo, IGenericRepository<ProductType> productTypeRepo, IMapper mapper)
|
||||||
{
|
{
|
||||||
_repo = repo;
|
_mapper = mapper;
|
||||||
|
_productTypeRepo = productTypeRepo;
|
||||||
|
_productBrandRepo = productBrandRepo;
|
||||||
|
_productsRepo = productsRepo;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public async Task<ActionResult<List<Product>>> GetProducts()
|
public async Task<ActionResult<IReadOnlyList<ProductToReturnDto>>> GetProducts()
|
||||||
{
|
{
|
||||||
var products = await _repo.GetProductsAync();
|
var spec = new ProductsWithTypesAndBrandsSpecification();
|
||||||
|
var products = await _productsRepo.ListAsync(spec);
|
||||||
return Ok(products);
|
return Ok(_mapper.Map<IReadOnlyList<Product>, IReadOnlyList<ProductToReturnDto>>(products));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{id}")]
|
[HttpGet("{id}")]
|
||||||
public async Task<ActionResult<Product>> GetProduct(int id)
|
public async Task<ActionResult<ProductToReturnDto>> GetProduct(int id)
|
||||||
{
|
{
|
||||||
return await _repo.GetProductByIdAsync(id);
|
var spec = new ProductsWithTypesAndBrandsSpecification(id);
|
||||||
|
var product = await _productsRepo.GetEntityWithSpec(spec);
|
||||||
|
return _mapper.Map<Product, ProductToReturnDto>(product);
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("brands")]
|
||||||
|
public async Task<ActionResult<IReadOnlyList<ProductBrand>>> GetProductBrands()
|
||||||
|
{
|
||||||
|
return Ok(await _productBrandRepo.ListAllAsync());
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("types")]
|
||||||
|
public async Task<ActionResult<IReadOnlyList<ProductType>>> GetProductTypes()
|
||||||
|
{
|
||||||
|
return Ok(await _productTypeRepo.ListAllAsync());
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
18
API/Dtos/ProductToReturnDto.cs
Normal file
18
API/Dtos/ProductToReturnDto.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace API.Dtos
|
||||||
|
{
|
||||||
|
public class ProductToReturnDto
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
|
public decimal Price { get; set; }
|
||||||
|
public string PictureUrl { get; set; }
|
||||||
|
public string ProductType { get; set; }
|
||||||
|
public string ProductBrand { get; set; }
|
||||||
|
}
|
||||||
|
}
|
16
API/Helpers/MappingProfiles.cs
Normal file
16
API/Helpers/MappingProfiles.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
using API.Dtos;
|
||||||
|
using AutoMapper;
|
||||||
|
using Core.Entities;
|
||||||
|
|
||||||
|
namespace API.Helpers
|
||||||
|
{
|
||||||
|
public class MappingProfiles : Profile
|
||||||
|
{
|
||||||
|
public MappingProfiles()
|
||||||
|
{
|
||||||
|
CreateMap<Product, ProductToReturnDto>()
|
||||||
|
.ForMember(d => d.ProductBrand, o => o.MapFrom(s => s.ProductBrand.Name))
|
||||||
|
.ForMember(d => d.ProductType, o => o.MapFrom(s => s.ProductType.Name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,4 @@
|
|||||||
|
using Infrastructure;
|
||||||
using Infrastructure.Data;
|
using Infrastructure.Data;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
@ -16,6 +17,7 @@ namespace API
|
|||||||
{
|
{
|
||||||
var context = services.GetRequiredService<StoreContext>();
|
var context = services.GetRequiredService<StoreContext>();
|
||||||
await context.Database.MigrateAsync();
|
await context.Database.MigrateAsync();
|
||||||
|
await StoreContextSeed.SeedAsync(context, loggerFactory);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
using API.Helpers;
|
||||||
using Core.Interfaces;
|
using Core.Interfaces;
|
||||||
using Infrastructure.Data;
|
using Infrastructure.Data;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
@ -21,6 +22,8 @@ namespace API
|
|||||||
services.AddControllers();
|
services.AddControllers();
|
||||||
services.AddDbContext<StoreContext>(x => x.UseSqlite(_config.GetConnectionString("DefaultConnection")));
|
services.AddDbContext<StoreContext>(x => x.UseSqlite(_config.GetConnectionString("DefaultConnection")));
|
||||||
services.AddScoped<iProductRepository, ProductRepository>();
|
services.AddScoped<iProductRepository, ProductRepository>();
|
||||||
|
services.AddScoped(typeof(IGenericRepository<>), (typeof(GenericRepository<>)));
|
||||||
|
services.AddAutoMapper(typeof(MappingProfiles));
|
||||||
services.AddSwaggerGen(c =>
|
services.AddSwaggerGen(c =>
|
||||||
{
|
{
|
||||||
c.SwaggerDoc("v1", new OpenApiInfo { Title = "WebAPIv5", Version = "v1" });
|
c.SwaggerDoc("v1", new OpenApiInfo { Title = "WebAPIv5", Version = "v1" });
|
||||||
|
Binary file not shown.
13
Core/Interfaces/IGenericRepository.cs
Normal file
13
Core/Interfaces/IGenericRepository.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
@ -6,5 +6,7 @@ namespace Core.Interfaces
|
|||||||
{
|
{
|
||||||
Task<Product> GetProductByIdAsync(int id);
|
Task<Product> GetProductByIdAsync(int id);
|
||||||
Task<IReadOnlyList<Product>> GetProductsAync();
|
Task<IReadOnlyList<Product>> GetProductsAync();
|
||||||
|
Task<IReadOnlyList<ProductBrand>> GetProductBrandsAsync();
|
||||||
|
Task<IReadOnlyList<ProductType>> GetProductTypesAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
23
Core/Specifications/BaseSpecification.cs
Normal file
23
Core/Specifications/BaseSpecification.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
Core/Specifications/ISpecification.cs
Normal file
11
Core/Specifications/ISpecification.cs
Normal 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; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
41
Infrastructure/Data/GenericRepository.cs
Normal file
41
Infrastructure/Data/GenericRepository.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -12,14 +12,30 @@ namespace Infrastructure.Data
|
|||||||
_context = context;
|
_context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<IReadOnlyList<ProductBrand>> GetProductBrandsAsync()
|
||||||
|
{
|
||||||
|
return await _context.ProductBrands.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<Product> GetProductByIdAsync(int id)
|
public async Task<Product> GetProductByIdAsync(int id)
|
||||||
{
|
{
|
||||||
return await _context.Products.FindAsync(id);
|
return await _context.Products
|
||||||
|
.Include(p => p.ProductType)
|
||||||
|
.Include(p => p.ProductBrand)
|
||||||
|
.FirstOrDefaultAsync(p => p.Id == id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IReadOnlyList<Product>> GetProductsAync()
|
public async Task<IReadOnlyList<Product>> GetProductsAync()
|
||||||
{
|
{
|
||||||
return await _context.Products.ToListAsync();
|
return await _context.Products
|
||||||
|
.Include(p => p.ProductType)
|
||||||
|
.Include(p => p.ProductBrand)
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IReadOnlyList<ProductType>> GetProductTypesAsync()
|
||||||
|
{
|
||||||
|
return await _context.ProductTypes.ToListAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
26
Infrastructure/Data/SeedData/brands.json
Normal file
26
Infrastructure/Data/SeedData/brands.json
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"Id": 1,
|
||||||
|
"Name": "Angular"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Id": 2,
|
||||||
|
"Name": "NetCore"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Id": 3,
|
||||||
|
"Name": "VS Code"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Id": 4,
|
||||||
|
"Name": "React"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Id": 5,
|
||||||
|
"Name": "Typescript"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Id": 6,
|
||||||
|
"Name": "Redis"
|
||||||
|
}
|
||||||
|
]
|
146
Infrastructure/Data/SeedData/products.json
Normal file
146
Infrastructure/Data/SeedData/products.json
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"Name": "Angular Speedster Board 2000",
|
||||||
|
"Description": "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas porttitor congue massa. Fusce posuere, magna sed pulvinar ultricies, purus lectus malesuada libero, sit amet commodo magna eros quis urna.",
|
||||||
|
"Price": 200,
|
||||||
|
"PictureUrl": "images/products/sb-ang1.png",
|
||||||
|
"ProductTypeId": 1,
|
||||||
|
"ProductBrandId": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "Green Angular Board 3000",
|
||||||
|
"Description": "Nunc viverra imperdiet enim. Fusce est. Vivamus a tellus.",
|
||||||
|
"Price": 150,
|
||||||
|
"PictureUrl": "images/products/sb-ang2.png",
|
||||||
|
"ProductTypeId": 1,
|
||||||
|
"ProductBrandId": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "Core Board Speed Rush 3",
|
||||||
|
"Description": "Suspendisse dui purus, scelerisque at, vulputate vitae, pretium mattis, nunc. Mauris eget neque at sem venenatis eleifend. Ut nonummy.",
|
||||||
|
"Price": 180,
|
||||||
|
"PictureUrl": "images/products/sb-core1.png",
|
||||||
|
"ProductTypeId": 1,
|
||||||
|
"ProductBrandId": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "Net Core Super Board",
|
||||||
|
"Description": "Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin pharetra nonummy pede. Mauris et orci.",
|
||||||
|
"Price": 300,
|
||||||
|
"PictureUrl": "images/products/sb-core2.png",
|
||||||
|
"ProductTypeId": 1,
|
||||||
|
"ProductBrandId": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "React Board Super Whizzy Fast",
|
||||||
|
"Description": "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas porttitor congue massa. Fusce posuere, magna sed pulvinar ultricies, purus lectus malesuada libero, sit amet commodo magna eros quis urna.",
|
||||||
|
"Price": 250,
|
||||||
|
"PictureUrl": "images/products/sb-react1.png",
|
||||||
|
"ProductTypeId": 1,
|
||||||
|
"ProductBrandId": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "Typescript Entry Board",
|
||||||
|
"Description": "Aenean nec lorem. In porttitor. Donec laoreet nonummy augue.",
|
||||||
|
"Price": 120,
|
||||||
|
"PictureUrl": "images/products/sb-ts1.png",
|
||||||
|
"ProductTypeId": 1,
|
||||||
|
"ProductBrandId": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "Core Blue Hat",
|
||||||
|
"Description": "Fusce posuere, magna sed pulvinar ultricies, purus lectus malesuada libero, sit amet commodo magna eros quis urna.",
|
||||||
|
"Price": 10,
|
||||||
|
"PictureUrl": "images/products/hat-core1.png",
|
||||||
|
"ProductTypeId": 2,
|
||||||
|
"ProductBrandId": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "Green React Woolen Hat",
|
||||||
|
"Description": "Suspendisse dui purus, scelerisque at, vulputate vitae, pretium mattis, nunc. Mauris eget neque at sem venenatis eleifend. Ut nonummy.",
|
||||||
|
"Price": 8,
|
||||||
|
"PictureUrl": "images/products/hat-react1.png",
|
||||||
|
"ProductTypeId": 2,
|
||||||
|
"ProductBrandId": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "Purple React Woolen Hat",
|
||||||
|
"Description": "Fusce posuere, magna sed pulvinar ultricies, purus lectus malesuada libero, sit amet commodo magna eros quis urna.",
|
||||||
|
"Price": 15,
|
||||||
|
"PictureUrl": "images/products/hat-react2.png",
|
||||||
|
"ProductTypeId": 2,
|
||||||
|
"ProductBrandId": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "Blue Code Gloves",
|
||||||
|
"Description": "Nunc viverra imperdiet enim. Fusce est. Vivamus a tellus.",
|
||||||
|
"Price": 18,
|
||||||
|
"PictureUrl": "images/products/glove-code1.png",
|
||||||
|
"ProductTypeId": 4,
|
||||||
|
"ProductBrandId": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "Green Code Gloves",
|
||||||
|
"Description": "Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin pharetra nonummy pede. Mauris et orci.",
|
||||||
|
"Price": 15,
|
||||||
|
"PictureUrl": "images/products/glove-code2.png",
|
||||||
|
"ProductTypeId": 4,
|
||||||
|
"ProductBrandId": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "Purple React Gloves",
|
||||||
|
"Description": "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas porttitor congue massa.",
|
||||||
|
"Price": 16,
|
||||||
|
"PictureUrl": "images/products/glove-react1.png",
|
||||||
|
"ProductTypeId": 4,
|
||||||
|
"ProductBrandId": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "Green React Gloves",
|
||||||
|
"Description": "Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin pharetra nonummy pede. Mauris et orci.",
|
||||||
|
"Price": 14,
|
||||||
|
"PictureUrl": "images/products/glove-react2.png",
|
||||||
|
"ProductTypeId": 4,
|
||||||
|
"ProductBrandId": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "Redis Red Boots",
|
||||||
|
"Description": "Suspendisse dui purus, scelerisque at, vulputate vitae, pretium mattis, nunc. Mauris eget neque at sem venenatis eleifend. Ut nonummy.",
|
||||||
|
"Price": 250,
|
||||||
|
"PictureUrl": "images/products/boot-redis1.png",
|
||||||
|
"ProductTypeId": 3,
|
||||||
|
"ProductBrandId": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "Core Red Boots",
|
||||||
|
"Description": "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas porttitor congue massa. Fusce posuere, magna sed pulvinar ultricies, purus lectus malesuada libero, sit amet commodo magna eros quis urna.",
|
||||||
|
"Price": 189.99,
|
||||||
|
"PictureUrl": "images/products/boot-core2.png",
|
||||||
|
"ProductTypeId": 3,
|
||||||
|
"ProductBrandId": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "Core Purple Boots",
|
||||||
|
"Description": "Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Proin pharetra nonummy pede. Mauris et orci.",
|
||||||
|
"Price": 199.99,
|
||||||
|
"PictureUrl": "images/products/boot-core1.png",
|
||||||
|
"ProductTypeId": 3,
|
||||||
|
"ProductBrandId": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "Angular Purple Boots",
|
||||||
|
"Description": "Aenean nec lorem. In porttitor. Donec laoreet nonummy augue.",
|
||||||
|
"Price": 150,
|
||||||
|
"PictureUrl": "images/products/boot-ang2.png",
|
||||||
|
"ProductTypeId": 3,
|
||||||
|
"ProductBrandId": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "Angular Blue Boots",
|
||||||
|
"Description": "Suspendisse dui purus, scelerisque at, vulputate vitae, pretium mattis, nunc. Mauris eget neque at sem venenatis eleifend. Ut nonummy.",
|
||||||
|
"Price": 180,
|
||||||
|
"PictureUrl": "images/products/boot-ang1.png",
|
||||||
|
"ProductTypeId": 3,
|
||||||
|
"ProductBrandId": 1
|
||||||
|
}
|
||||||
|
]
|
18
Infrastructure/Data/SeedData/types.json
Normal file
18
Infrastructure/Data/SeedData/types.json
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"Id": 1,
|
||||||
|
"Name": "Boards"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Id": 2,
|
||||||
|
"Name": "Hats"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Id": 3,
|
||||||
|
"Name": "Boots"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Id": 4,
|
||||||
|
"Name": "Gloves"
|
||||||
|
}
|
||||||
|
]
|
23
Infrastructure/Data/SpecificationEvaluator.cs
Normal file
23
Infrastructure/Data/SpecificationEvaluator.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
57
Infrastructure/Data/StoreContextSeed.cs
Normal file
57
Infrastructure/Data/StoreContextSeed.cs
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
using Core.Entities;
|
||||||
|
using Infrastructure.Data;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace Infrastructure
|
||||||
|
{
|
||||||
|
public class StoreContextSeed
|
||||||
|
{
|
||||||
|
public static async Task SeedAsync(StoreContext context, ILoggerFactory loggerFactory)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!context.ProductBrands.Any())
|
||||||
|
{
|
||||||
|
var brandsData = File.ReadAllText("../Infrastructure/Data/SeedData/brands.json");
|
||||||
|
var brands = JsonSerializer.Deserialize<List<ProductBrand>>(brandsData);
|
||||||
|
foreach (var item in brands)
|
||||||
|
{
|
||||||
|
context.ProductBrands.Add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!context.ProductTypes.Any())
|
||||||
|
{
|
||||||
|
var typesData = File.ReadAllText("../Infrastructure/Data/SeedData/types.json");
|
||||||
|
var types = JsonSerializer.Deserialize<List<ProductType>>(typesData);
|
||||||
|
foreach (var item in types)
|
||||||
|
{
|
||||||
|
context.ProductTypes.Add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!context.Products.Any())
|
||||||
|
{
|
||||||
|
var productsData = File.ReadAllText("../Infrastructure/Data/SeedData/products.json");
|
||||||
|
var products = JsonSerializer.Deserialize<List<Product>>(productsData);
|
||||||
|
foreach (var item in products)
|
||||||
|
{
|
||||||
|
context.Products.Add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var logger = loggerFactory.CreateLogger<StoreContextSeed>();
|
||||||
|
logger.LogError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user