Skip to content

Commit

Permalink
Upgrade to use Specification 4.0.0 (dotnet-architecture#444)
Browse files Browse the repository at this point in the history
  • Loading branch information
ardalis authored Jul 31, 2020
1 parent e520126 commit 754c845
Show file tree
Hide file tree
Showing 15 changed files with 63 additions and 52 deletions.
2 changes: 1 addition & 1 deletion src/ApplicationCore/ApplicationCore.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

<ItemGroup>
<PackageReference Include="Ardalis.GuardClauses" Version="1.5.0" />
<PackageReference Include="Ardalis.Specification" Version="3.0.0" />
<PackageReference Include="Ardalis.Specification" Version="4.0.0" />
<PackageReference Include="MediatR" Version="8.0.2" />
<PackageReference Include="System.Security.Claims" Version="4.3.0" />
<PackageReference Include="System.Text.Json" Version="4.7.2" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,20 @@

namespace Microsoft.eShopWeb.ApplicationCore.Specifications
{
public sealed class BasketWithItemsSpecification : BaseSpecification<Basket>
public sealed class BasketWithItemsSpecification : Specification<Basket>
{
public BasketWithItemsSpecification(int basketId) : base(b => b.Id == basketId)
public BasketWithItemsSpecification(int basketId)
{
AddInclude(b => b.Items);
Query
.Where(b => b.Id == basketId)
.Include(b => b.Items);
}

public BasketWithItemsSpecification(string buyerId) : base(b => b.BuyerId == buyerId)
public BasketWithItemsSpecification(string buyerId)
{
AddInclude(b => b.Items);
Query
.Where(b => b.BuyerId == buyerId)
.Include(b => b.Items);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@

namespace Microsoft.eShopWeb.ApplicationCore.Specifications
{
public class CatalogFilterPaginatedSpecification : BaseSpecification<CatalogItem>
public class CatalogFilterPaginatedSpecification : Specification<CatalogItem>
{
public CatalogFilterPaginatedSpecification(int skip, int take, int? brandId, int? typeId)
: base(i => (!brandId.HasValue || i.CatalogBrandId == brandId) &&
(!typeId.HasValue || i.CatalogTypeId == typeId))
: base()
{
ApplyPaging(skip, take);
Query
.Where(i => (!brandId.HasValue || i.CatalogBrandId == brandId) &&
(!typeId.HasValue || i.CatalogTypeId == typeId))
.Paginate(skip, take);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@

namespace Microsoft.eShopWeb.ApplicationCore.Specifications
{

public class CatalogFilterSpecification : BaseSpecification<CatalogItem>
public class CatalogFilterSpecification : Specification<CatalogItem>
{
public CatalogFilterSpecification(int? brandId, int? typeId)
: base(i => (!brandId.HasValue || i.CatalogBrandId == brandId) &&
(!typeId.HasValue || i.CatalogTypeId == typeId))
{
Query.Where(i => (!brandId.HasValue || i.CatalogBrandId == brandId) &&
(!typeId.HasValue || i.CatalogTypeId == typeId));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@

namespace Microsoft.eShopWeb.ApplicationCore.Specifications
{
public class CatalogItemsSpecification : BaseSpecification<CatalogItem>
public class CatalogItemsSpecification : Specification<CatalogItem>
{
public CatalogItemsSpecification(params int[] ids) : base(c => ids.Contains(c.Id))
public CatalogItemsSpecification(params int[] ids)
{

Query.Where(c => ids.Contains(c.Id));
}
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
using Ardalis.Specification;
using Ardalis.Specification.QueryExtensions.Include;
using Microsoft.eShopWeb.ApplicationCore.Entities.OrderAggregate;

namespace Microsoft.eShopWeb.ApplicationCore.Specifications
{
public class CustomerOrdersWithItemsSpecification : BaseSpecification<Order>
public class CustomerOrdersWithItemsSpecification : Specification<Order>
{
public CustomerOrdersWithItemsSpecification(string buyerId)
: base(o => o.BuyerId == buyerId)
{
AddIncludes(query => query.Include(o => o.OrderItems)
.ThenInclude(i => i.ItemOrdered));
Query.Where(o => o.BuyerId == buyerId)
.Include(o => o.OrderItems)
.ThenInclude(i => i.ItemOrdered);
}
}
}
14 changes: 8 additions & 6 deletions src/Infrastructure/Data/EfRepository.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Ardalis.Specification;
using Ardalis.Specification.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.eShopWeb.ApplicationCore.Entities;
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
Expand Down Expand Up @@ -34,13 +35,13 @@ public async Task<IReadOnlyList<T>> ListAllAsync()

public async Task<IReadOnlyList<T>> ListAsync(ISpecification<T> spec)
{
var specificationResult = await ApplySpecification(spec);
var specificationResult = ApplySpecification(spec);
return await specificationResult.ToListAsync();
}

public async Task<int> CountAsync(ISpecification<T> spec)
{
var specificationResult = await ApplySpecification(spec);
var specificationResult = ApplySpecification(spec);
return await specificationResult.CountAsync();
}

Expand All @@ -66,19 +67,20 @@ public async Task DeleteAsync(T entity)

public async Task<T> FirstAsync(ISpecification<T> spec)
{
var specificationResult = await ApplySpecification(spec);
var specificationResult = ApplySpecification(spec);
return await specificationResult.FirstAsync();
}

public async Task<T> FirstOrDefaultAsync(ISpecification<T> spec)
{
var specificationResult = await ApplySpecification(spec);
var specificationResult = ApplySpecification(spec);
return await specificationResult.FirstOrDefaultAsync();
}

private async Task<IQueryable<T>> ApplySpecification(ISpecification<T> spec)
private IQueryable<T> ApplySpecification(ISpecification<T> spec)
{
return await EfSpecificationEvaluator<T>.GetQuery(_dbContext.Set<T>().AsQueryable(), spec);
var evaluator = new SpecificationEvaluator<T>();
return evaluator.GetQuery(_dbContext.Set<T>().AsQueryable(), spec);
}
}
}
3 changes: 2 additions & 1 deletion src/Infrastructure/Infrastructure.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@

<ItemGroup>
<PackageReference Include="Ardalis.EFCore.Extensions" Version="1.1.0" />
<PackageReference Include="Ardalis.Specification" Version="3.0.0" />
<PackageReference Include="Ardalis.Specification" Version="4.0.0" />
<PackageReference Include="Ardalis.Specification.EntityFrameworkCore" Version="4.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Identity" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="3.1.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.5" />
Expand Down
2 changes: 1 addition & 1 deletion src/Web/Areas/Identity/Pages/Account/Login.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
Note that for demo purposes you don't need to register and can login with these credentials:
</p>
<p>
User: <b>demouser@microsoft.com</b>
User: <b>demouser@microsoft.com</b> OR <b>admin@microsoft.com</b>
</p>
<p>
Password: <b>Pass@word1</b>
Expand Down
2 changes: 1 addition & 1 deletion src/Web/Web.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<ItemGroup>
<PackageReference Include="Ardalis.ApiEndpoints" Version="1.0.0" />
<PackageReference Include="Ardalis.ListStartupServices" Version="1.1.3" />
<PackageReference Include="Ardalis.Specification" Version="3.0.0" />
<PackageReference Include="Ardalis.Specification" Version="4.0.0" />
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="7.0.0" />

<PackageReference Include="MediatR" Version="8.0.2" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,25 @@
using System.Linq;
using Xunit;
using Moq;
using Ardalis.Specification.EntityFrameworkCore;

namespace Microsoft.eShopWeb.UnitTests
namespace Microsoft.eShopWeb.UnitTests.ApplicationCore.Specifications
{
public class BasketWithItems
{
private readonly int _testBasketId = 123;
private readonly string _buyerId = "Test buyerId";

// tests with specifications can use an evaluator or just WhereExpressions.FirstOrDefault if only one
private readonly SpecificationEvaluator<Basket> _evaluator = new SpecificationEvaluator<Basket>();

[Fact]
public void MatchesBasketWithGivenBasketId()
{
var spec = new BasketWithItemsSpecification(_testBasketId);

var result = GetTestBasketCollection()
.AsQueryable()
.FirstOrDefault(spec.Criterias.FirstOrDefault());
var result = _evaluator.GetQuery(GetTestBasketCollection().AsQueryable(), spec)
.FirstOrDefault();

Assert.NotNull(result);
Assert.Equal(_testBasketId, result.Id);
Expand All @@ -31,19 +34,19 @@ public void MatchesNoBasketsIfBasketIdNotPresent()
int badBasketId = -1;
var spec = new BasketWithItemsSpecification(badBasketId);

Assert.False(GetTestBasketCollection()
.AsQueryable()
.Any(spec.Criterias.FirstOrDefault()));
var result = _evaluator.GetQuery(GetTestBasketCollection().AsQueryable(), spec)
.Any();

Assert.False(result);
}

[Fact]
public void MatchesBasketWithGivenBuyerId()
{
var spec = new BasketWithItemsSpecification(_buyerId);

var result = GetTestBasketCollection()
.AsQueryable()
.FirstOrDefault(spec.Criterias.FirstOrDefault());
var result = _evaluator.GetQuery(GetTestBasketCollection().AsQueryable(), spec)
.FirstOrDefault();

Assert.NotNull(result);
Assert.Equal(_buyerId, result.BuyerId);
Expand All @@ -55,9 +58,10 @@ public void MatchesNoBasketsIfBuyerIdNotPresent()
string badBuyerId = "badBuyerId";
var spec = new BasketWithItemsSpecification(badBuyerId);

Assert.False(GetTestBasketCollection()
.AsQueryable()
.Any(spec.Criterias.FirstOrDefault()));
var result = _evaluator.GetQuery(GetTestBasketCollection().AsQueryable(), spec)
.Any();

Assert.False(result);
}

public List<Basket> GetTestBasketCollection()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public void ReturnsAllCatalogItems()

var result = GetTestCollection()
.AsQueryable()
.Where(spec.Criterias.FirstOrDefault());
.Where(spec.WhereExpressions.FirstOrDefault());

Assert.NotNull(result);
Assert.Equal(4, result.ToList().Count);
Expand All @@ -27,7 +27,7 @@ public void Returns2CatalogItemsWithSameBrandAndTypeId()

var result = GetTestCollection()
.AsQueryable()
.Where(spec.Criterias.FirstOrDefault());
.Where(spec.WhereExpressions.FirstOrDefault());

Assert.NotNull(result);
Assert.Equal(2, result.ToList().Count);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using System.Linq;
using Xunit;

namespace Microsoft.eShopWeb.UnitTests
namespace Microsoft.eShopWeb.UnitTests.ApplicationCore.Specifications
{
public class CatalogFilterSpecification
{
Expand All @@ -21,7 +21,7 @@ public void MatchesExpectedNumberOfItems(int? brandId, int? typeId, int expected

var result = GetTestItemCollection()
.AsQueryable()
.Where(spec.Criterias.FirstOrDefault());
.Where(spec.WhereExpressions.FirstOrDefault());

Assert.Equal(expectedCount, result.Count());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public void MatchesSpecificCatalogItem()

var result = GetTestCollection()
.AsQueryable()
.Where(spec.Criterias.FirstOrDefault());
.Where(spec.WhereExpressions.FirstOrDefault());

Assert.NotNull(result);
Assert.Single(result.ToList());
Expand All @@ -30,7 +30,7 @@ public void MatchesAllCatalogItems()

var result = GetTestCollection()
.AsQueryable()
.Where(spec.Criterias.FirstOrDefault());
.Where(spec.WhereExpressions.FirstOrDefault());

Assert.NotNull(result);
Assert.Equal(2, result.ToList().Count);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public void ReturnsOrderWithOrderedItem()

var result = GetTestCollection()
.AsQueryable()
.FirstOrDefault(spec.Criterias.FirstOrDefault());
.FirstOrDefault(spec.WhereExpressions.FirstOrDefault());

Assert.NotNull(result);
Assert.NotNull(result.OrderItems);
Expand All @@ -32,7 +32,7 @@ public void ReturnsAllOrderWithAllOrderedItem()

var result = GetTestCollection()
.AsQueryable()
.Where(spec.Criterias.FirstOrDefault())
.Where(spec.WhereExpressions.FirstOrDefault())
.ToList();

Assert.NotNull(result);
Expand Down

0 comments on commit 754c845

Please sign in to comment.