Using Base Specification Class (#56)
* Ardalis/upgrade1 (#44) * Upgrading to netcore 2.0 Updating repository to support async options and refactoring to use it. * Starting work on tracking customer orders feature. * Cleaning up some bugs Working on basket view component implementation * Fixing up styles, especially for basket in header. * Adding Order Features (#47) * Working on order model binding from checkout page - WIP * Small layout tweaks (#43) * Updating quantities implemented. * Fixed basket widget count * Order History (#49) * working on creating and viewing orders. * Working on wiring up listing of orders * List orders page works as expected. Needed to support ThenInclude scenarios. Currently using strings. * Remove non-icon basket link from header Add comments to EF query logic * Refactoring to use base specification type * minor cleanup
This commit is contained in:
@@ -9,6 +9,5 @@ namespace ApplicationCore.Interfaces
|
|||||||
Expression<Func<T, bool>> Criteria { get; }
|
Expression<Func<T, bool>> Criteria { get; }
|
||||||
List<Expression<Func<T, object>>> Includes { get; }
|
List<Expression<Func<T, object>>> Includes { get; }
|
||||||
List<string> IncludeStrings { get; }
|
List<string> IncludeStrings { get; }
|
||||||
void AddInclude(Expression<Func<T, object>> includeExpression);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
27
src/ApplicationCore/Specifications/BaseSpecification.cs
Normal file
27
src/ApplicationCore/Specifications/BaseSpecification.cs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
using ApplicationCore.Interfaces;
|
||||||
|
using System;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace ApplicationCore.Specifications
|
||||||
|
{
|
||||||
|
public abstract class BaseSpecification<T> : ISpecification<T>
|
||||||
|
{
|
||||||
|
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>>>();
|
||||||
|
public List<string> IncludeStrings { get; } = new List<string>();
|
||||||
|
|
||||||
|
protected virtual void AddInclude(Expression<Func<T, object>> includeExpression)
|
||||||
|
{
|
||||||
|
Includes.Add(includeExpression);
|
||||||
|
}
|
||||||
|
protected virtual void AddInclude(string includeString)
|
||||||
|
{
|
||||||
|
IncludeStrings.Add(includeString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,39 +1,18 @@
|
|||||||
using ApplicationCore.Interfaces;
|
using Microsoft.eShopWeb.ApplicationCore.Entities;
|
||||||
using Microsoft.eShopWeb.ApplicationCore.Entities;
|
|
||||||
using System;
|
|
||||||
using System.Linq.Expressions;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using ApplicationCore.Entities.OrderAggregate;
|
|
||||||
|
|
||||||
namespace ApplicationCore.Specifications
|
namespace ApplicationCore.Specifications
|
||||||
{
|
{
|
||||||
public class BasketWithItemsSpecification : ISpecification<Basket>
|
public class BasketWithItemsSpecification : BaseSpecification<Basket>
|
||||||
{
|
{
|
||||||
public BasketWithItemsSpecification(int basketId)
|
public BasketWithItemsSpecification(int basketId)
|
||||||
|
:base(b => b.Id == basketId)
|
||||||
{
|
{
|
||||||
BasketId = basketId;
|
|
||||||
AddInclude(b => b.Items);
|
AddInclude(b => b.Items);
|
||||||
}
|
}
|
||||||
public BasketWithItemsSpecification(string buyerId)
|
public BasketWithItemsSpecification(string buyerId)
|
||||||
|
:base(b => b.BuyerId == buyerId)
|
||||||
{
|
{
|
||||||
BuyerId = buyerId;
|
|
||||||
AddInclude(b => b.Items);
|
AddInclude(b => b.Items);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int? BasketId { get; }
|
|
||||||
public string BuyerId { get; }
|
|
||||||
|
|
||||||
public Expression<Func<Basket, bool>> Criteria => b =>
|
|
||||||
(BasketId.HasValue && b.Id == BasketId.Value)
|
|
||||||
|| (BuyerId != null && b.BuyerId == BuyerId);
|
|
||||||
|
|
||||||
public List<Expression<Func<Basket, object>>> Includes { get; } = new List<Expression<Func<Basket, object>>>();
|
|
||||||
|
|
||||||
public List<string> IncludeStrings { get; } = new List<string>();
|
|
||||||
|
|
||||||
public void AddInclude(Expression<Func<Basket, object>> includeExpression)
|
|
||||||
{
|
|
||||||
Includes.Add(includeExpression);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,34 +1,14 @@
|
|||||||
using ApplicationCore.Interfaces;
|
using Microsoft.eShopWeb.ApplicationCore.Entities;
|
||||||
using Microsoft.eShopWeb.ApplicationCore.Entities;
|
|
||||||
using System;
|
|
||||||
using System.Linq.Expressions;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace ApplicationCore.Specifications
|
namespace ApplicationCore.Specifications
|
||||||
{
|
{
|
||||||
|
|
||||||
public class CatalogFilterSpecification : ISpecification<CatalogItem>
|
public class CatalogFilterSpecification : BaseSpecification<CatalogItem>
|
||||||
{
|
{
|
||||||
public CatalogFilterSpecification(int? brandId, int? typeId)
|
public CatalogFilterSpecification(int? brandId, int? typeId)
|
||||||
|
: base(i => (!brandId.HasValue || i.CatalogBrandId == brandId) &&
|
||||||
|
(!typeId.HasValue || i.CatalogTypeId == typeId))
|
||||||
{
|
{
|
||||||
BrandId = brandId;
|
|
||||||
TypeId = typeId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int? BrandId { get; }
|
|
||||||
public int? TypeId { get; }
|
|
||||||
|
|
||||||
public Expression<Func<CatalogItem, bool>> Criteria =>
|
|
||||||
i => (!BrandId.HasValue || i.CatalogBrandId == BrandId) &&
|
|
||||||
(!TypeId.HasValue || i.CatalogTypeId == TypeId);
|
|
||||||
|
|
||||||
public List<Expression<Func<CatalogItem, object>>> Includes { get; } = new List<Expression<Func<CatalogItem, object>>>();
|
|
||||||
|
|
||||||
public List<string> IncludeStrings { get; } = new List<string>();
|
|
||||||
|
|
||||||
public void AddInclude(Expression<Func<CatalogItem, object>> includeExpression)
|
|
||||||
{
|
|
||||||
Includes.Add(includeExpression);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,35 +1,14 @@
|
|||||||
using ApplicationCore.Interfaces;
|
using ApplicationCore.Entities.OrderAggregate;
|
||||||
using System;
|
|
||||||
using System.Linq.Expressions;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using ApplicationCore.Entities.OrderAggregate;
|
|
||||||
|
|
||||||
namespace ApplicationCore.Specifications
|
namespace ApplicationCore.Specifications
|
||||||
{
|
{
|
||||||
public class CustomerOrdersWithItemsSpecification : ISpecification<Order>
|
public class CustomerOrdersWithItemsSpecification : BaseSpecification<Order>
|
||||||
{
|
{
|
||||||
private readonly string _buyerId;
|
|
||||||
|
|
||||||
public CustomerOrdersWithItemsSpecification(string buyerId)
|
public CustomerOrdersWithItemsSpecification(string buyerId)
|
||||||
|
: base(o => o.BuyerId == buyerId)
|
||||||
{
|
{
|
||||||
_buyerId = buyerId;
|
|
||||||
AddInclude(o => o.OrderItems);
|
AddInclude(o => o.OrderItems);
|
||||||
AddInclude("OrderItems.ItemOrdered");
|
AddInclude("OrderItems.ItemOrdered");
|
||||||
}
|
}
|
||||||
|
|
||||||
public Expression<Func<Order, bool>> Criteria => o => o.BuyerId == _buyerId;
|
|
||||||
|
|
||||||
public List<Expression<Func<Order, object>>> Includes { get; } = new List<Expression<Func<Order, object>>>();
|
|
||||||
public List<string> IncludeStrings { get; } = new List<string>();
|
|
||||||
|
|
||||||
public void AddInclude(Expression<Func<Order, object>> includeExpression)
|
|
||||||
{
|
|
||||||
Includes.Add(includeExpression);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddInclude(string includeString)
|
|
||||||
{
|
|
||||||
IncludeStrings.Add(includeString);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,25 +43,34 @@ namespace Infrastructure.Data
|
|||||||
|
|
||||||
public IEnumerable<T> List(ISpecification<T> spec)
|
public IEnumerable<T> List(ISpecification<T> spec)
|
||||||
{
|
{
|
||||||
|
// fetch a Queryable that includes all expression-based includes
|
||||||
var queryableResultWithIncludes = spec.Includes
|
var queryableResultWithIncludes = spec.Includes
|
||||||
.Aggregate(_dbContext.Set<T>().AsQueryable(),
|
.Aggregate(_dbContext.Set<T>().AsQueryable(),
|
||||||
(current, include) => current.Include(include));
|
(current, include) => current.Include(include));
|
||||||
|
|
||||||
|
// modify the IQueryable to include any string-based include statements
|
||||||
var secondaryResult = spec.IncludeStrings
|
var secondaryResult = spec.IncludeStrings
|
||||||
.Aggregate(queryableResultWithIncludes,
|
.Aggregate(queryableResultWithIncludes,
|
||||||
(current, include) => current.Include(include));
|
(current, include) => current.Include(include));
|
||||||
|
|
||||||
|
// return the result of the query using the specification's criteria expression
|
||||||
return secondaryResult
|
return secondaryResult
|
||||||
.Where(spec.Criteria)
|
.Where(spec.Criteria)
|
||||||
.AsEnumerable();
|
.AsEnumerable();
|
||||||
}
|
}
|
||||||
public async Task<List<T>> ListAsync(ISpecification<T> spec)
|
public async Task<List<T>> ListAsync(ISpecification<T> spec)
|
||||||
{
|
{
|
||||||
|
// fetch a Queryable that includes all expression-based includes
|
||||||
var queryableResultWithIncludes = spec.Includes
|
var queryableResultWithIncludes = spec.Includes
|
||||||
.Aggregate(_dbContext.Set<T>().AsQueryable(),
|
.Aggregate(_dbContext.Set<T>().AsQueryable(),
|
||||||
(current, include) => current.Include(include));
|
(current, include) => current.Include(include));
|
||||||
|
|
||||||
|
// modify the IQueryable to include any string-based include statements
|
||||||
var secondaryResult = spec.IncludeStrings
|
var secondaryResult = spec.IncludeStrings
|
||||||
.Aggregate(queryableResultWithIncludes,
|
.Aggregate(queryableResultWithIncludes,
|
||||||
(current, include) => current.Include(include));
|
(current, include) => current.Include(include));
|
||||||
|
|
||||||
|
// return the result of the query using the specification's criteria expression
|
||||||
return await secondaryResult
|
return await secondaryResult
|
||||||
.Where(spec.Criteria)
|
.Where(spec.Criteria)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|||||||
@@ -33,8 +33,6 @@
|
|||||||
</a>
|
</a>
|
||||||
</section>
|
</section>
|
||||||
@await Html.PartialAsync("_LoginPartial")
|
@await Html.PartialAsync("_LoginPartial")
|
||||||
<section class="col-lg-1 col-md-3 col-xs-6"><a asp-controller="Basket" asp-action="Index">Basket</a></section>
|
|
||||||
|
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|||||||
Reference in New Issue
Block a user