diff --git a/src/ApplicationCore/Interfaces/IBasketQueryService.cs b/src/ApplicationCore/Interfaces/IBasketQueryService.cs
new file mode 100644
index 0000000..6136df7
--- /dev/null
+++ b/src/ApplicationCore/Interfaces/IBasketQueryService.cs
@@ -0,0 +1,12 @@
+using System.Threading.Tasks;
+
+namespace Microsoft.eShopWeb.ApplicationCore.Interfaces;
+
+///
+/// Specific query used to fetch count without running in memory
+///
+public interface IBasketQueryService
+{
+ Task CountTotalBasketItems(string username);
+}
+
diff --git a/src/Infrastructure/Data/Queries/BasketQueryService.cs b/src/Infrastructure/Data/Queries/BasketQueryService.cs
new file mode 100644
index 0000000..9f6c4d9
--- /dev/null
+++ b/src/Infrastructure/Data/Queries/BasketQueryService.cs
@@ -0,0 +1,31 @@
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.eShopWeb.ApplicationCore.Interfaces;
+
+namespace Microsoft.eShopWeb.Infrastructure.Data.Queries;
+
+public class BasketQueryService : IBasketQueryService
+{
+ private readonly CatalogContext _dbContext;
+
+ public BasketQueryService(CatalogContext dbContext)
+ {
+ _dbContext = dbContext;
+ }
+
+ ///
+ /// This method performs the sum on the database rather than in memory
+ ///
+ ///
+ ///
+ public async Task CountTotalBasketItems(string username)
+ {
+ var totalItems = await _dbContext.Baskets
+ .Where(basket => basket.BuyerId == username)
+ .SelectMany(item => item.Items)
+ .SumAsync(sum => sum.Quantity);
+
+ return totalItems;
+ }
+}
diff --git a/src/Web/Configuration/ConfigureCoreServices.cs b/src/Web/Configuration/ConfigureCoreServices.cs
index b9b843f..f38657d 100644
--- a/src/Web/Configuration/ConfigureCoreServices.cs
+++ b/src/Web/Configuration/ConfigureCoreServices.cs
@@ -1,6 +1,7 @@
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
using Microsoft.eShopWeb.ApplicationCore.Services;
using Microsoft.eShopWeb.Infrastructure.Data;
+using Microsoft.eShopWeb.Infrastructure.Data.Queries;
using Microsoft.eShopWeb.Infrastructure.Logging;
using Microsoft.eShopWeb.Infrastructure.Services;
using Microsoft.Extensions.Configuration;
@@ -18,6 +19,7 @@ public static class ConfigureCoreServices
services.AddScoped();
services.AddScoped();
+ services.AddScoped();
services.AddSingleton(new UriComposer(configuration.Get()));
services.AddScoped(typeof(IAppLogger<>), typeof(LoggerAdapter<>));
services.AddTransient();
diff --git a/src/Web/Interfaces/IBasketViewModelService.cs b/src/Web/Interfaces/IBasketViewModelService.cs
index a5cb8b4..85d1c87 100644
--- a/src/Web/Interfaces/IBasketViewModelService.cs
+++ b/src/Web/Interfaces/IBasketViewModelService.cs
@@ -7,5 +7,6 @@ namespace Microsoft.eShopWeb.Web.Interfaces;
public interface IBasketViewModelService
{
Task GetOrCreateBasketForUser(string userName);
+ Task CountTotalBasketItems(string username);
Task Map(Basket basket);
}
diff --git a/src/Web/Pages/Shared/Components/BasketComponent/Basket.cs b/src/Web/Pages/Shared/Components/BasketComponent/Basket.cs
index 4b6c6c6..519a335 100644
--- a/src/Web/Pages/Shared/Components/BasketComponent/Basket.cs
+++ b/src/Web/Pages/Shared/Components/BasketComponent/Basket.cs
@@ -2,27 +2,21 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
-using Microsoft.eShopWeb.ApplicationCore.Interfaces;
-using Microsoft.eShopWeb.ApplicationCore.Specifications;
using Microsoft.eShopWeb.Infrastructure.Identity;
using Microsoft.eShopWeb.Web.Interfaces;
using Microsoft.eShopWeb.Web.ViewModels;
-using BasketEntity = Microsoft.eShopWeb.ApplicationCore.Entities.BasketAggregate.Basket;
namespace Microsoft.eShopWeb.Web.Pages.Shared.Components.BasketComponent;
public class Basket : ViewComponent
{
- private readonly IBasketViewModelService _basketViewModelService;
- private readonly IReadRepository _basketRepository;
+ private readonly IBasketViewModelService _basketService;
private readonly SignInManager _signInManager;
- public Basket(IBasketViewModelService basketViewModelService,
- IReadRepository basketRepository,
- SignInManager signInManager)
+ public Basket(IBasketViewModelService basketService,
+ SignInManager signInManager)
{
- _basketViewModelService = basketViewModelService;
- _basketRepository = basketRepository;
+ _basketService = basketService;
_signInManager = signInManager;
}
@@ -39,26 +33,18 @@ public class Basket : ViewComponent
{
if (_signInManager.IsSignedIn(HttpContext.User))
{
- var userNameSpec = new BasketWithItemsSpecification(User.Identity.Name);
-
- var userBasket = await _basketRepository.GetBySpecAsync(userNameSpec);
- if (userBasket == null) return 0;
- return userBasket.TotalItems;
+ return await _basketService.CountTotalBasketItems(User.Identity.Name);
}
string anonymousId = GetAnnonymousIdFromCookie();
if (anonymousId == null)
return 0;
- var anonymousSpec = new BasketWithItemsSpecification(anonymousId);
- var anonymousBasket = await _basketRepository.GetBySpecAsync(anonymousSpec);
- if (anonymousBasket == null) return 0;
- return anonymousBasket.TotalItems;
+ return await _basketService.CountTotalBasketItems(anonymousId);
}
private string GetAnnonymousIdFromCookie()
{
- // TODO: Add a prefix to anonymous cookie values so they cannot collide with user names
if (Request.Cookies.ContainsKey(Constants.BASKET_COOKIENAME))
{
var id = Request.Cookies[Constants.BASKET_COOKIENAME];
diff --git a/src/Web/Services/BasketViewModelService.cs b/src/Web/Services/BasketViewModelService.cs
index ab12285..06cfdf4 100644
--- a/src/Web/Services/BasketViewModelService.cs
+++ b/src/Web/Services/BasketViewModelService.cs
@@ -14,14 +14,17 @@ public class BasketViewModelService : IBasketViewModelService
{
private readonly IRepository _basketRepository;
private readonly IUriComposer _uriComposer;
- private readonly IReadRepository _itemRepository;
+ private readonly IBasketQueryService _basketQueryService;
+ private readonly IRepository _itemRepository;
public BasketViewModelService(IRepository basketRepository,
- IReadRepository itemRepository,
- IUriComposer uriComposer)
+ IRepository itemRepository,
+ IUriComposer uriComposer,
+ IBasketQueryService basketQueryService)
{
_basketRepository = basketRepository;
_uriComposer = uriComposer;
+ _basketQueryService = basketQueryService;
_itemRepository = itemRepository;
}
@@ -83,4 +86,11 @@ public class BasketViewModelService : IBasketViewModelService
Items = await GetBasketItems(basket.Items)
};
}
+
+ public async Task CountTotalBasketItems(string username)
+ {
+ var counter = await _basketQueryService.CountTotalBasketItems(username);
+
+ return counter;
+ }
}