Skip to content

Commit

Permalink
Using Base Specification Class (dotnet-architecture#56)
Browse files Browse the repository at this point in the history
* Ardalis/upgrade1 (dotnet-architecture#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 (dotnet-architecture#47)

* Working on order model binding from checkout page - WIP

* Small layout tweaks (dotnet-architecture#43)

* Updating quantities implemented.

* Fixed basket widget count

* Order History (dotnet-architecture#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
  • Loading branch information
ardalis authored Oct 18, 2017
1 parent d52dbb1 commit 964173f
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 76 deletions.
1 change: 0 additions & 1 deletion src/ApplicationCore/Interfaces/ISpecification.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,5 @@ public interface ISpecification<T>
Expression<Func<T, bool>> Criteria { get; }
List<Expression<Func<T, object>>> Includes { get; }
List<string> IncludeStrings { get; }
void AddInclude(Expression<Func<T, object>> includeExpression);
}
}
27 changes: 27 additions & 0 deletions src/ApplicationCore/Specifications/BaseSpecification.cs
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
29 changes: 4 additions & 25 deletions src/ApplicationCore/Specifications/BasketWithItemsSpecification.cs
Original file line number Diff line number Diff line change
@@ -1,39 +1,18 @@
using ApplicationCore.Interfaces;
using Microsoft.eShopWeb.ApplicationCore.Entities;
using System;
using System.Linq.Expressions;
using System.Collections.Generic;
using ApplicationCore.Entities.OrderAggregate;
using Microsoft.eShopWeb.ApplicationCore.Entities;

namespace ApplicationCore.Specifications
{
public class BasketWithItemsSpecification : ISpecification<Basket>
public class BasketWithItemsSpecification : BaseSpecification<Basket>
{
public BasketWithItemsSpecification(int basketId)
:base(b => b.Id == basketId)
{
BasketId = basketId;
AddInclude(b => b.Items);
}
public BasketWithItemsSpecification(string buyerId)
:base(b => b.BuyerId == buyerId)
{
BuyerId = buyerId;
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);
}
}
}
28 changes: 4 additions & 24 deletions src/ApplicationCore/Specifications/CatalogFilterSpecification.cs
Original file line number Diff line number Diff line change
@@ -1,34 +1,14 @@
using ApplicationCore.Interfaces;
using Microsoft.eShopWeb.ApplicationCore.Entities;
using System;
using System.Linq.Expressions;
using System.Collections.Generic;
using Microsoft.eShopWeb.ApplicationCore.Entities;

namespace ApplicationCore.Specifications
{

public class CatalogFilterSpecification : ISpecification<CatalogItem>
public class CatalogFilterSpecification : BaseSpecification<CatalogItem>
{
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);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,35 +1,14 @@
using ApplicationCore.Interfaces;
using System;
using System.Linq.Expressions;
using System.Collections.Generic;
using ApplicationCore.Entities.OrderAggregate;
using ApplicationCore.Entities.OrderAggregate;

namespace ApplicationCore.Specifications
{
public class CustomerOrdersWithItemsSpecification : ISpecification<Order>
public class CustomerOrdersWithItemsSpecification : BaseSpecification<Order>
{
private readonly string _buyerId;

public CustomerOrdersWithItemsSpecification(string buyerId)
: base(o => o.BuyerId == buyerId)
{
_buyerId = buyerId;
AddInclude(o => o.OrderItems);
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);
}
}
}
9 changes: 9 additions & 0 deletions src/Infrastructure/Data/EfRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,25 +43,34 @@ public async Task<List<T>> ListAllAsync()

public IEnumerable<T> List(ISpecification<T> spec)
{
// fetch a Queryable that includes all expression-based includes
var queryableResultWithIncludes = spec.Includes
.Aggregate(_dbContext.Set<T>().AsQueryable(),
(current, include) => current.Include(include));

// modify the IQueryable to include any string-based include statements
var secondaryResult = spec.IncludeStrings
.Aggregate(queryableResultWithIncludes,
(current, include) => current.Include(include));

// return the result of the query using the specification's criteria expression
return secondaryResult
.Where(spec.Criteria)
.AsEnumerable();
}
public async Task<List<T>> ListAsync(ISpecification<T> spec)
{
// fetch a Queryable that includes all expression-based includes
var queryableResultWithIncludes = spec.Includes
.Aggregate(_dbContext.Set<T>().AsQueryable(),
(current, include) => current.Include(include));

// modify the IQueryable to include any string-based include statements
var secondaryResult = spec.IncludeStrings
.Aggregate(queryableResultWithIncludes,
(current, include) => current.Include(include));

// return the result of the query using the specification's criteria expression
return await secondaryResult
.Where(spec.Criteria)
.ToListAsync();
Expand Down
2 changes: 0 additions & 2 deletions src/Web/Views/Shared/_Layout.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@
</a>
</section>
@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>
</div>
</header>
Expand Down

0 comments on commit 964173f

Please sign in to comment.