Upgrade to use Specification 4.0.0 (#444)
This commit is contained in:
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Ardalis.GuardClauses" Version="1.5.0" />
|
<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="MediatR" Version="8.0.2" />
|
||||||
<PackageReference Include="System.Security.Claims" Version="4.3.0" />
|
<PackageReference Include="System.Security.Claims" Version="4.3.0" />
|
||||||
<PackageReference Include="System.Text.Json" Version="4.7.2" />
|
<PackageReference Include="System.Text.Json" Version="4.7.2" />
|
||||||
|
|||||||
@@ -3,16 +3,20 @@ using Microsoft.eShopWeb.ApplicationCore.Entities.BasketAggregate;
|
|||||||
|
|
||||||
namespace Microsoft.eShopWeb.ApplicationCore.Specifications
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,13 +3,15 @@ using Microsoft.eShopWeb.ApplicationCore.Entities;
|
|||||||
|
|
||||||
namespace Microsoft.eShopWeb.ApplicationCore.Specifications
|
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)
|
public CatalogFilterPaginatedSpecification(int skip, int take, int? brandId, int? typeId)
|
||||||
: base(i => (!brandId.HasValue || i.CatalogBrandId == brandId) &&
|
: base()
|
||||||
(!typeId.HasValue || i.CatalogTypeId == typeId))
|
|
||||||
{
|
{
|
||||||
ApplyPaging(skip, take);
|
Query
|
||||||
|
.Where(i => (!brandId.HasValue || i.CatalogBrandId == brandId) &&
|
||||||
|
(!typeId.HasValue || i.CatalogTypeId == typeId))
|
||||||
|
.Paginate(skip, take);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,13 +3,12 @@ using Microsoft.eShopWeb.ApplicationCore.Entities;
|
|||||||
|
|
||||||
namespace Microsoft.eShopWeb.ApplicationCore.Specifications
|
namespace Microsoft.eShopWeb.ApplicationCore.Specifications
|
||||||
{
|
{
|
||||||
|
public class CatalogFilterSpecification : Specification<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))
|
|
||||||
{
|
{
|
||||||
|
Query.Where(i => (!brandId.HasValue || i.CatalogBrandId == brandId) &&
|
||||||
|
(!typeId.HasValue || i.CatalogTypeId == typeId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ using System.Linq;
|
|||||||
|
|
||||||
namespace Microsoft.eShopWeb.ApplicationCore.Specifications
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
using Ardalis.Specification;
|
using Ardalis.Specification;
|
||||||
using Ardalis.Specification.QueryExtensions.Include;
|
|
||||||
using Microsoft.eShopWeb.ApplicationCore.Entities.OrderAggregate;
|
using Microsoft.eShopWeb.ApplicationCore.Entities.OrderAggregate;
|
||||||
|
|
||||||
namespace Microsoft.eShopWeb.ApplicationCore.Specifications
|
namespace Microsoft.eShopWeb.ApplicationCore.Specifications
|
||||||
{
|
{
|
||||||
public class CustomerOrdersWithItemsSpecification : BaseSpecification<Order>
|
public class CustomerOrdersWithItemsSpecification : Specification<Order>
|
||||||
{
|
{
|
||||||
public CustomerOrdersWithItemsSpecification(string buyerId)
|
public CustomerOrdersWithItemsSpecification(string buyerId)
|
||||||
: base(o => o.BuyerId == buyerId)
|
|
||||||
{
|
{
|
||||||
AddIncludes(query => query.Include(o => o.OrderItems)
|
Query.Where(o => o.BuyerId == buyerId)
|
||||||
.ThenInclude(i => i.ItemOrdered));
|
.Include(o => o.OrderItems)
|
||||||
|
.ThenInclude(i => i.ItemOrdered);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Ardalis.Specification;
|
using Ardalis.Specification;
|
||||||
|
using Ardalis.Specification.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.eShopWeb.ApplicationCore.Entities;
|
using Microsoft.eShopWeb.ApplicationCore.Entities;
|
||||||
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
|
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
|
||||||
@@ -34,13 +35,13 @@ namespace Microsoft.eShopWeb.Infrastructure.Data
|
|||||||
|
|
||||||
public async Task<IReadOnlyList<T>> ListAsync(ISpecification<T> spec)
|
public async Task<IReadOnlyList<T>> ListAsync(ISpecification<T> spec)
|
||||||
{
|
{
|
||||||
var specificationResult = await ApplySpecification(spec);
|
var specificationResult = ApplySpecification(spec);
|
||||||
return await specificationResult.ToListAsync();
|
return await specificationResult.ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> CountAsync(ISpecification<T> spec)
|
public async Task<int> CountAsync(ISpecification<T> spec)
|
||||||
{
|
{
|
||||||
var specificationResult = await ApplySpecification(spec);
|
var specificationResult = ApplySpecification(spec);
|
||||||
return await specificationResult.CountAsync();
|
return await specificationResult.CountAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,19 +67,20 @@ namespace Microsoft.eShopWeb.Infrastructure.Data
|
|||||||
|
|
||||||
public async Task<T> FirstAsync(ISpecification<T> spec)
|
public async Task<T> FirstAsync(ISpecification<T> spec)
|
||||||
{
|
{
|
||||||
var specificationResult = await ApplySpecification(spec);
|
var specificationResult = ApplySpecification(spec);
|
||||||
return await specificationResult.FirstAsync();
|
return await specificationResult.FirstAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<T> FirstOrDefaultAsync(ISpecification<T> spec)
|
public async Task<T> FirstOrDefaultAsync(ISpecification<T> spec)
|
||||||
{
|
{
|
||||||
var specificationResult = await ApplySpecification(spec);
|
var specificationResult = ApplySpecification(spec);
|
||||||
return await specificationResult.FirstOrDefaultAsync();
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,7 +7,8 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Ardalis.EFCore.Extensions" Version="1.1.0" />
|
<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" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="3.1.5" />
|
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="3.1.5" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.5" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.5" />
|
||||||
|
|||||||
@@ -47,7 +47,7 @@
|
|||||||
Note that for demo purposes you don't need to register and can login with these credentials:
|
Note that for demo purposes you don't need to register and can login with these credentials:
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
User: <b>demouser@microsoft.com</b>
|
User: <b>demouser@microsoft.com</b> OR <b>admin@microsoft.com</b>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Password: <b>Pass@word1</b>
|
Password: <b>Pass@word1</b>
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Ardalis.ApiEndpoints" Version="1.0.0" />
|
<PackageReference Include="Ardalis.ApiEndpoints" Version="1.0.0" />
|
||||||
<PackageReference Include="Ardalis.ListStartupServices" Version="1.1.3" />
|
<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="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="7.0.0" />
|
||||||
|
|
||||||
<PackageReference Include="MediatR" Version="8.0.2" />
|
<PackageReference Include="MediatR" Version="8.0.2" />
|
||||||
|
|||||||
@@ -4,22 +4,25 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
using Moq;
|
using Moq;
|
||||||
|
using Ardalis.Specification.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace Microsoft.eShopWeb.UnitTests
|
namespace Microsoft.eShopWeb.UnitTests.ApplicationCore.Specifications
|
||||||
{
|
{
|
||||||
public class BasketWithItems
|
public class BasketWithItems
|
||||||
{
|
{
|
||||||
private readonly int _testBasketId = 123;
|
private readonly int _testBasketId = 123;
|
||||||
private readonly string _buyerId = "Test buyerId";
|
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]
|
[Fact]
|
||||||
public void MatchesBasketWithGivenBasketId()
|
public void MatchesBasketWithGivenBasketId()
|
||||||
{
|
{
|
||||||
var spec = new BasketWithItemsSpecification(_testBasketId);
|
var spec = new BasketWithItemsSpecification(_testBasketId);
|
||||||
|
|
||||||
var result = GetTestBasketCollection()
|
var result = _evaluator.GetQuery(GetTestBasketCollection().AsQueryable(), spec)
|
||||||
.AsQueryable()
|
.FirstOrDefault();
|
||||||
.FirstOrDefault(spec.Criterias.FirstOrDefault());
|
|
||||||
|
|
||||||
Assert.NotNull(result);
|
Assert.NotNull(result);
|
||||||
Assert.Equal(_testBasketId, result.Id);
|
Assert.Equal(_testBasketId, result.Id);
|
||||||
@@ -31,9 +34,10 @@ namespace Microsoft.eShopWeb.UnitTests
|
|||||||
int badBasketId = -1;
|
int badBasketId = -1;
|
||||||
var spec = new BasketWithItemsSpecification(badBasketId);
|
var spec = new BasketWithItemsSpecification(badBasketId);
|
||||||
|
|
||||||
Assert.False(GetTestBasketCollection()
|
var result = _evaluator.GetQuery(GetTestBasketCollection().AsQueryable(), spec)
|
||||||
.AsQueryable()
|
.Any();
|
||||||
.Any(spec.Criterias.FirstOrDefault()));
|
|
||||||
|
Assert.False(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -41,9 +45,8 @@ namespace Microsoft.eShopWeb.UnitTests
|
|||||||
{
|
{
|
||||||
var spec = new BasketWithItemsSpecification(_buyerId);
|
var spec = new BasketWithItemsSpecification(_buyerId);
|
||||||
|
|
||||||
var result = GetTestBasketCollection()
|
var result = _evaluator.GetQuery(GetTestBasketCollection().AsQueryable(), spec)
|
||||||
.AsQueryable()
|
.FirstOrDefault();
|
||||||
.FirstOrDefault(spec.Criterias.FirstOrDefault());
|
|
||||||
|
|
||||||
Assert.NotNull(result);
|
Assert.NotNull(result);
|
||||||
Assert.Equal(_buyerId, result.BuyerId);
|
Assert.Equal(_buyerId, result.BuyerId);
|
||||||
@@ -55,9 +58,10 @@ namespace Microsoft.eShopWeb.UnitTests
|
|||||||
string badBuyerId = "badBuyerId";
|
string badBuyerId = "badBuyerId";
|
||||||
var spec = new BasketWithItemsSpecification(badBuyerId);
|
var spec = new BasketWithItemsSpecification(badBuyerId);
|
||||||
|
|
||||||
Assert.False(GetTestBasketCollection()
|
var result = _evaluator.GetQuery(GetTestBasketCollection().AsQueryable(), spec)
|
||||||
.AsQueryable()
|
.Any();
|
||||||
.Any(spec.Criterias.FirstOrDefault()));
|
|
||||||
|
Assert.False(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Basket> GetTestBasketCollection()
|
public List<Basket> GetTestBasketCollection()
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ namespace Microsoft.eShopWeb.UnitTests.ApplicationCore.Specifications
|
|||||||
|
|
||||||
var result = GetTestCollection()
|
var result = GetTestCollection()
|
||||||
.AsQueryable()
|
.AsQueryable()
|
||||||
.Where(spec.Criterias.FirstOrDefault());
|
.Where(spec.WhereExpressions.FirstOrDefault());
|
||||||
|
|
||||||
Assert.NotNull(result);
|
Assert.NotNull(result);
|
||||||
Assert.Equal(4, result.ToList().Count);
|
Assert.Equal(4, result.ToList().Count);
|
||||||
@@ -27,7 +27,7 @@ namespace Microsoft.eShopWeb.UnitTests.ApplicationCore.Specifications
|
|||||||
|
|
||||||
var result = GetTestCollection()
|
var result = GetTestCollection()
|
||||||
.AsQueryable()
|
.AsQueryable()
|
||||||
.Where(spec.Criterias.FirstOrDefault());
|
.Where(spec.WhereExpressions.FirstOrDefault());
|
||||||
|
|
||||||
Assert.NotNull(result);
|
Assert.NotNull(result);
|
||||||
Assert.Equal(2, result.ToList().Count);
|
Assert.Equal(2, result.ToList().Count);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.eShopWeb.UnitTests
|
namespace Microsoft.eShopWeb.UnitTests.ApplicationCore.Specifications
|
||||||
{
|
{
|
||||||
public class CatalogFilterSpecification
|
public class CatalogFilterSpecification
|
||||||
{
|
{
|
||||||
@@ -21,7 +21,7 @@ namespace Microsoft.eShopWeb.UnitTests
|
|||||||
|
|
||||||
var result = GetTestItemCollection()
|
var result = GetTestItemCollection()
|
||||||
.AsQueryable()
|
.AsQueryable()
|
||||||
.Where(spec.Criterias.FirstOrDefault());
|
.Where(spec.WhereExpressions.FirstOrDefault());
|
||||||
|
|
||||||
Assert.Equal(expectedCount, result.Count());
|
Assert.Equal(expectedCount, result.Count());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace Microsoft.eShopWeb.UnitTests.ApplicationCore.Specifications
|
|||||||
|
|
||||||
var result = GetTestCollection()
|
var result = GetTestCollection()
|
||||||
.AsQueryable()
|
.AsQueryable()
|
||||||
.Where(spec.Criterias.FirstOrDefault());
|
.Where(spec.WhereExpressions.FirstOrDefault());
|
||||||
|
|
||||||
Assert.NotNull(result);
|
Assert.NotNull(result);
|
||||||
Assert.Single(result.ToList());
|
Assert.Single(result.ToList());
|
||||||
@@ -30,7 +30,7 @@ namespace Microsoft.eShopWeb.UnitTests.ApplicationCore.Specifications
|
|||||||
|
|
||||||
var result = GetTestCollection()
|
var result = GetTestCollection()
|
||||||
.AsQueryable()
|
.AsQueryable()
|
||||||
.Where(spec.Criterias.FirstOrDefault());
|
.Where(spec.WhereExpressions.FirstOrDefault());
|
||||||
|
|
||||||
Assert.NotNull(result);
|
Assert.NotNull(result);
|
||||||
Assert.Equal(2, result.ToList().Count);
|
Assert.Equal(2, result.ToList().Count);
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ namespace Microsoft.eShopWeb.UnitTests.ApplicationCore.Specifications
|
|||||||
|
|
||||||
var result = GetTestCollection()
|
var result = GetTestCollection()
|
||||||
.AsQueryable()
|
.AsQueryable()
|
||||||
.FirstOrDefault(spec.Criterias.FirstOrDefault());
|
.FirstOrDefault(spec.WhereExpressions.FirstOrDefault());
|
||||||
|
|
||||||
Assert.NotNull(result);
|
Assert.NotNull(result);
|
||||||
Assert.NotNull(result.OrderItems);
|
Assert.NotNull(result.OrderItems);
|
||||||
@@ -32,7 +32,7 @@ namespace Microsoft.eShopWeb.UnitTests.ApplicationCore.Specifications
|
|||||||
|
|
||||||
var result = GetTestCollection()
|
var result = GetTestCollection()
|
||||||
.AsQueryable()
|
.AsQueryable()
|
||||||
.Where(spec.Criterias.FirstOrDefault())
|
.Where(spec.WhereExpressions.FirstOrDefault())
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
Assert.NotNull(result);
|
Assert.NotNull(result);
|
||||||
|
|||||||
Reference in New Issue
Block a user