diff --git a/src/ApplicationCore/Interfaces/ISpecification.cs b/src/ApplicationCore/Interfaces/ISpecification.cs index 5b11734..f9a2167 100644 --- a/src/ApplicationCore/Interfaces/ISpecification.cs +++ b/src/ApplicationCore/Interfaces/ISpecification.cs @@ -9,6 +9,5 @@ namespace ApplicationCore.Interfaces Expression> Criteria { get; } List>> Includes { get; } List IncludeStrings { get; } - void AddInclude(Expression> includeExpression); } } diff --git a/src/ApplicationCore/Specifications/BaseSpecification.cs b/src/ApplicationCore/Specifications/BaseSpecification.cs new file mode 100644 index 0000000..e39a86d --- /dev/null +++ b/src/ApplicationCore/Specifications/BaseSpecification.cs @@ -0,0 +1,27 @@ +using ApplicationCore.Interfaces; +using System; +using System.Linq.Expressions; +using System.Collections.Generic; + +namespace ApplicationCore.Specifications +{ + public abstract class BaseSpecification : ISpecification + { + public BaseSpecification(Expression> criteria) + { + Criteria = criteria; + } + public Expression> Criteria { get; } + public List>> Includes { get; } = new List>>(); + public List IncludeStrings { get; } = new List(); + + protected virtual void AddInclude(Expression> includeExpression) + { + Includes.Add(includeExpression); + } + protected virtual void AddInclude(string includeString) + { + IncludeStrings.Add(includeString); + } + } +} diff --git a/src/ApplicationCore/Specifications/BasketWithItemsSpecification.cs b/src/ApplicationCore/Specifications/BasketWithItemsSpecification.cs index a44fb77..5608dc6 100644 --- a/src/ApplicationCore/Specifications/BasketWithItemsSpecification.cs +++ b/src/ApplicationCore/Specifications/BasketWithItemsSpecification.cs @@ -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 + public class BasketWithItemsSpecification : BaseSpecification { 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> Criteria => b => - (BasketId.HasValue && b.Id == BasketId.Value) - || (BuyerId != null && b.BuyerId == BuyerId); - - public List>> Includes { get; } = new List>>(); - - public List IncludeStrings { get; } = new List(); - - public void AddInclude(Expression> includeExpression) - { - Includes.Add(includeExpression); - } } } diff --git a/src/ApplicationCore/Specifications/CatalogFilterSpecification.cs b/src/ApplicationCore/Specifications/CatalogFilterSpecification.cs index 54e1f86..efcba8c 100644 --- a/src/ApplicationCore/Specifications/CatalogFilterSpecification.cs +++ b/src/ApplicationCore/Specifications/CatalogFilterSpecification.cs @@ -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 + public class CatalogFilterSpecification : BaseSpecification { 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> Criteria => - i => (!BrandId.HasValue || i.CatalogBrandId == BrandId) && - (!TypeId.HasValue || i.CatalogTypeId == TypeId); - - public List>> Includes { get; } = new List>>(); - - public List IncludeStrings { get; } = new List(); - - public void AddInclude(Expression> includeExpression) - { - Includes.Add(includeExpression); } } } diff --git a/src/ApplicationCore/Specifications/CustomerOrdersWithItemsSpecification.cs b/src/ApplicationCore/Specifications/CustomerOrdersWithItemsSpecification.cs index abfa9b6..df234c4 100644 --- a/src/ApplicationCore/Specifications/CustomerOrdersWithItemsSpecification.cs +++ b/src/ApplicationCore/Specifications/CustomerOrdersWithItemsSpecification.cs @@ -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 + public class CustomerOrdersWithItemsSpecification : BaseSpecification { - private readonly string _buyerId; - public CustomerOrdersWithItemsSpecification(string buyerId) + : base(o => o.BuyerId == buyerId) { - _buyerId = buyerId; AddInclude(o => o.OrderItems); AddInclude("OrderItems.ItemOrdered"); } - - public Expression> Criteria => o => o.BuyerId == _buyerId; - - public List>> Includes { get; } = new List>>(); - public List IncludeStrings { get; } = new List(); - - public void AddInclude(Expression> includeExpression) - { - Includes.Add(includeExpression); - } - - public void AddInclude(string includeString) - { - IncludeStrings.Add(includeString); - } } } diff --git a/src/Infrastructure/Data/EfRepository.cs b/src/Infrastructure/Data/EfRepository.cs index cdc84fa..b0cecfa 100644 --- a/src/Infrastructure/Data/EfRepository.cs +++ b/src/Infrastructure/Data/EfRepository.cs @@ -43,25 +43,34 @@ namespace Infrastructure.Data public IEnumerable List(ISpecification spec) { + // fetch a Queryable that includes all expression-based includes var queryableResultWithIncludes = spec.Includes .Aggregate(_dbContext.Set().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> ListAsync(ISpecification spec) { + // fetch a Queryable that includes all expression-based includes var queryableResultWithIncludes = spec.Includes .Aggregate(_dbContext.Set().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(); diff --git a/src/Web/Views/Shared/_Layout.cshtml b/src/Web/Views/Shared/_Layout.cshtml index 998deb2..8803d10 100644 --- a/src/Web/Views/Shared/_Layout.cshtml +++ b/src/Web/Views/Shared/_Layout.cshtml @@ -33,8 +33,6 @@ @await Html.PartialAsync("_LoginPartial") -
Basket
-