replace counter by specific query to avoid load each items in memory (#611)
* replace counter by specific query to avoid load each items in memory * Create IBasketQueryService
This commit is contained in:
9
src/ApplicationCore/Interfaces/IBasketQueryService.cs
Normal file
9
src/ApplicationCore/Interfaces/IBasketQueryService.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Interfaces
|
||||
{
|
||||
public interface IBasketQueryService
|
||||
{
|
||||
Task<int> CountTotalBasketItems(string username);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
using Microsoft.eShopWeb.ApplicationCore.Entities.OrderAggregate;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.eShopWeb.ApplicationCore.Interfaces
|
||||
{
|
||||
|
||||
//public interface IOrderRepository : IAsyncRepository<Order>
|
||||
//{
|
||||
// Task<Order> GetByIdWithItemsAsync(int id);
|
||||
//}
|
||||
}
|
||||
27
src/Infrastructure/Data/BasketQueryService.cs
Normal file
27
src/Infrastructure/Data/BasketQueryService.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.eShopWeb.Infrastructure.Data
|
||||
{
|
||||
public class BasketQueryService : IBasketQueryService
|
||||
{
|
||||
private readonly CatalogContext _dbContext;
|
||||
|
||||
public BasketQueryService(CatalogContext dbContext)
|
||||
{
|
||||
_dbContext = dbContext;
|
||||
}
|
||||
|
||||
public async Task<int> CountTotalBasketItems(string username)
|
||||
{
|
||||
var totalItems = await _dbContext.Baskets
|
||||
.Where(basket => basket.BuyerId == username)
|
||||
.SelectMany(item => item.Items)
|
||||
.SumAsync(sum => sum.Quantity);
|
||||
|
||||
return totalItems;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,94 +1,12 @@
|
||||
using Ardalis.Specification;
|
||||
using Ardalis.Specification.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Entities;
|
||||
using Ardalis.Specification.EntityFrameworkCore;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.eShopWeb.Infrastructure.Data
|
||||
{
|
||||
public class EfRepository<T> : RepositoryBase<T>, IReadRepository<T>, IRepository<T> where T : class, IAggregateRoot
|
||||
{
|
||||
{
|
||||
public EfRepository(CatalogContext dbContext) : base(dbContext)
|
||||
{
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// "There's some repetition here - couldn't we have some the sync methods call the async?"
|
||||
/// https://blogs.msdn.microsoft.com/pfxteam/2012/04/13/should-i-expose-synchronous-wrappers-for-asynchronous-methods/
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
// public class EfRepository<T> : IAsyncRepository<T> where T : BaseEntity, IAggregateRoot
|
||||
// {
|
||||
// protected readonly CatalogContext _dbContext;
|
||||
|
||||
// public EfRepository(CatalogContext dbContext)
|
||||
// {
|
||||
// _dbContext = dbContext;
|
||||
// }
|
||||
|
||||
// public virtual async Task<T> GetByIdAsync(int id, CancellationToken cancellationToken = default)
|
||||
// {
|
||||
// var keyValues = new object[] { id };
|
||||
// return await _dbContext.Set<T>().FindAsync(keyValues, cancellationToken);
|
||||
// }
|
||||
|
||||
// public async Task<IReadOnlyList<T>> ListAllAsync(CancellationToken cancellationToken = default)
|
||||
// {
|
||||
// return await _dbContext.Set<T>().ToListAsync(cancellationToken);
|
||||
// }
|
||||
|
||||
// public async Task<IReadOnlyList<T>> ListAsync(ISpecification<T> spec, CancellationToken cancellationToken = default)
|
||||
// {
|
||||
// var specificationResult = ApplySpecification(spec);
|
||||
// return await specificationResult.ToListAsync(cancellationToken);
|
||||
// }
|
||||
|
||||
// public async Task<int> CountAsync(ISpecification<T> spec, CancellationToken cancellationToken = default)
|
||||
// {
|
||||
// var specificationResult = ApplySpecification(spec);
|
||||
// return await specificationResult.CountAsync(cancellationToken);
|
||||
// }
|
||||
|
||||
// public async Task<T> AddAsync(T entity, CancellationToken cancellationToken = default)
|
||||
// {
|
||||
// await _dbContext.Set<T>().AddAsync(entity, cancellationToken);
|
||||
// await _dbContext.SaveChangesAsync(cancellationToken);
|
||||
|
||||
// return entity;
|
||||
// }
|
||||
|
||||
// public async Task UpdateAsync(T entity, CancellationToken cancellationToken = default)
|
||||
// {
|
||||
// _dbContext.Entry(entity).State = EntityState.Modified;
|
||||
// await _dbContext.SaveChangesAsync(cancellationToken);
|
||||
// }
|
||||
|
||||
// public async Task DeleteAsync(T entity, CancellationToken cancellationToken = default)
|
||||
// {
|
||||
// _dbContext.Set<T>().Remove(entity);
|
||||
// await _dbContext.SaveChangesAsync(cancellationToken);
|
||||
// }
|
||||
|
||||
// public async Task<T> FirstAsync(ISpecification<T> spec, CancellationToken cancellationToken = default)
|
||||
// {
|
||||
// var specificationResult = ApplySpecification(spec);
|
||||
// return await specificationResult.FirstAsync(cancellationToken);
|
||||
// }
|
||||
|
||||
// public async Task<T> FirstOrDefaultAsync(ISpecification<T> spec, CancellationToken cancellationToken = default)
|
||||
// {
|
||||
// var specificationResult = ApplySpecification(spec);
|
||||
// return await specificationResult.FirstOrDefaultAsync(cancellationToken);
|
||||
// }
|
||||
|
||||
// private IQueryable<T> ApplySpecification(ISpecification<T> spec)
|
||||
// {
|
||||
// var evaluator = new SpecificationEvaluator<T>();
|
||||
// return evaluator.GetQuery(_dbContext.Set<T>().AsQueryable(), spec);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Entities.OrderAggregate;
|
||||
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.eShopWeb.Infrastructure.Data
|
||||
{
|
||||
//public class OrderRepository : EfRepository<Order>, IOrderRepository
|
||||
//{
|
||||
// public OrderRepository(CatalogContext dbContext) : base(dbContext)
|
||||
// {
|
||||
// }
|
||||
|
||||
// public Task<Order> GetByIdWithItemsAsync(int id)
|
||||
// {
|
||||
// return _dbContext.Orders
|
||||
// .Include(o => o.OrderItems)
|
||||
// .ThenInclude(i => i.ItemOrdered)
|
||||
// .FirstOrDefaultAsync(x => x.Id == id);
|
||||
// }
|
||||
//}
|
||||
}
|
||||
@@ -13,13 +13,12 @@ namespace Microsoft.eShopWeb.Web.Configuration
|
||||
public static IServiceCollection AddCoreServices(this IServiceCollection services,
|
||||
IConfiguration configuration)
|
||||
{
|
||||
//services.AddScoped(typeof(IAsyncRepository<>), typeof(EfRepository<>));
|
||||
services.AddScoped(typeof(IReadRepository<>), typeof(EfRepository<>));
|
||||
services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>));
|
||||
|
||||
services.AddScoped<IBasketService, BasketService>();
|
||||
services.AddScoped<IOrderService, OrderService>();
|
||||
//services.AddScoped<IOrderRepository, OrderRepository>();
|
||||
services.AddScoped<IBasketQueryService, BasketQueryService>();
|
||||
services.AddSingleton<IUriComposer>(new UriComposer(configuration.Get<CatalogSettings>()));
|
||||
services.AddScoped(typeof(IAppLogger<>), typeof(LoggerAdapter<>));
|
||||
services.AddTransient<IEmailSender, EmailSender>();
|
||||
|
||||
@@ -14,14 +14,17 @@ namespace Microsoft.eShopWeb.Web.Services
|
||||
{
|
||||
private readonly IRepository<Basket> _basketRepository;
|
||||
private readonly IUriComposer _uriComposer;
|
||||
private readonly IBasketQueryService _basketQueryService;
|
||||
private readonly IRepository<CatalogItem> _itemRepository;
|
||||
|
||||
public BasketViewModelService(IRepository<Basket> basketRepository,
|
||||
IRepository<CatalogItem> itemRepository,
|
||||
IUriComposer uriComposer)
|
||||
IUriComposer uriComposer,
|
||||
IBasketQueryService basketQueryService)
|
||||
{
|
||||
_basketRepository = basketRepository;
|
||||
_uriComposer = uriComposer;
|
||||
_basketQueryService = basketQueryService;
|
||||
_itemRepository = itemRepository;
|
||||
}
|
||||
|
||||
@@ -86,11 +89,9 @@ namespace Microsoft.eShopWeb.Web.Services
|
||||
|
||||
public async Task<int> CountTotalBasketItems(string username)
|
||||
{
|
||||
var basketSpec = new BasketWithItemsSpecification(username);
|
||||
var basket = await _basketRepository.GetBySpecAsync(basketSpec);
|
||||
if (basket == null)
|
||||
return 0;
|
||||
return basket.Items.Sum(i => i.Quantity);
|
||||
var counter = await _basketQueryService.CountTotalBasketItems(username);
|
||||
|
||||
return counter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user