Merge pull request #221 from dotnet-architecture/remove-irepository
Removing IRepository in favor of IAsyncRepository
This commit is contained in:
@@ -1,17 +0,0 @@
|
|||||||
using Microsoft.eShopWeb.ApplicationCore.Entities;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Microsoft.eShopWeb.ApplicationCore.Interfaces
|
|
||||||
{
|
|
||||||
public interface IRepository<T> where T : BaseEntity
|
|
||||||
{
|
|
||||||
T GetById(int id);
|
|
||||||
T GetSingleBySpec(ISpecification<T> spec);
|
|
||||||
IEnumerable<T> ListAll();
|
|
||||||
IEnumerable<T> List(ISpecification<T> spec);
|
|
||||||
T Add(T entity);
|
|
||||||
void Update(T entity);
|
|
||||||
void Delete(T entity);
|
|
||||||
int Count(ISpecification<T> spec);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -15,10 +15,8 @@ namespace Microsoft.eShopWeb.ApplicationCore.Services
|
|||||||
private readonly IAsyncRepository<BasketItem> _basketItemRepository;
|
private readonly IAsyncRepository<BasketItem> _basketItemRepository;
|
||||||
private readonly IUriComposer _uriComposer;
|
private readonly IUriComposer _uriComposer;
|
||||||
private readonly IAppLogger<BasketService> _logger;
|
private readonly IAppLogger<BasketService> _logger;
|
||||||
private readonly IRepository<CatalogItem> _itemRepository;
|
|
||||||
|
|
||||||
public BasketService(IAsyncRepository<Basket> basketRepository,
|
public BasketService(IAsyncRepository<Basket> basketRepository,
|
||||||
IRepository<CatalogItem> itemRepository,
|
|
||||||
IUriComposer uriComposer,
|
IUriComposer uriComposer,
|
||||||
IAppLogger<BasketService> logger,
|
IAppLogger<BasketService> logger,
|
||||||
IAsyncRepository<BasketItem> basketItemRepository)
|
IAsyncRepository<BasketItem> basketItemRepository)
|
||||||
@@ -26,7 +24,6 @@ namespace Microsoft.eShopWeb.ApplicationCore.Services
|
|||||||
_basketRepository = basketRepository;
|
_basketRepository = basketRepository;
|
||||||
_uriComposer = uriComposer;
|
_uriComposer = uriComposer;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_itemRepository = itemRepository;
|
|
||||||
_basketItemRepository = basketItemRepository;
|
_basketItemRepository = basketItemRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ namespace Microsoft.eShopWeb.Infrastructure.Data
|
|||||||
/// https://blogs.msdn.microsoft.com/pfxteam/2012/04/13/should-i-expose-synchronous-wrappers-for-asynchronous-methods/
|
/// https://blogs.msdn.microsoft.com/pfxteam/2012/04/13/should-i-expose-synchronous-wrappers-for-asynchronous-methods/
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <typeparam name="T"></typeparam>
|
/// <typeparam name="T"></typeparam>
|
||||||
public class EfRepository<T> : IRepository<T>, IAsyncRepository<T> where T : BaseEntity
|
public class EfRepository<T> : IAsyncRepository<T> where T : BaseEntity
|
||||||
{
|
{
|
||||||
protected readonly CatalogContext _dbContext;
|
protected readonly CatalogContext _dbContext;
|
||||||
|
|
||||||
@@ -20,59 +20,27 @@ namespace Microsoft.eShopWeb.Infrastructure.Data
|
|||||||
{
|
{
|
||||||
_dbContext = dbContext;
|
_dbContext = dbContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual T GetById(int id)
|
|
||||||
{
|
|
||||||
return _dbContext.Set<T>().Find(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public T GetSingleBySpec(ISpecification<T> spec)
|
|
||||||
{
|
|
||||||
return List(spec).FirstOrDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual async Task<T> GetByIdAsync(int id)
|
public virtual async Task<T> GetByIdAsync(int id)
|
||||||
{
|
{
|
||||||
return await _dbContext.Set<T>().FindAsync(id);
|
return await _dbContext.Set<T>().FindAsync(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<T> ListAll()
|
|
||||||
{
|
|
||||||
return _dbContext.Set<T>().AsEnumerable();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<IReadOnlyList<T>> ListAllAsync()
|
public async Task<IReadOnlyList<T>> ListAllAsync()
|
||||||
{
|
{
|
||||||
return await _dbContext.Set<T>().ToListAsync();
|
return await _dbContext.Set<T>().ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<T> List(ISpecification<T> spec)
|
|
||||||
{
|
|
||||||
return ApplySpecification(spec).AsEnumerable();
|
|
||||||
}
|
|
||||||
public async Task<IReadOnlyList<T>> ListAsync(ISpecification<T> spec)
|
public async Task<IReadOnlyList<T>> ListAsync(ISpecification<T> spec)
|
||||||
{
|
{
|
||||||
return await ApplySpecification(spec).ToListAsync();
|
return await ApplySpecification(spec).ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Count(ISpecification<T> spec)
|
|
||||||
{
|
|
||||||
return ApplySpecification(spec).Count();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<int> CountAsync(ISpecification<T> spec)
|
public async Task<int> CountAsync(ISpecification<T> spec)
|
||||||
{
|
{
|
||||||
return await ApplySpecification(spec).CountAsync();
|
return await ApplySpecification(spec).CountAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public T Add(T entity)
|
|
||||||
{
|
|
||||||
_dbContext.Set<T>().Add(entity);
|
|
||||||
_dbContext.SaveChanges();
|
|
||||||
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<T> AddAsync(T entity)
|
public async Task<T> AddAsync(T entity)
|
||||||
{
|
{
|
||||||
_dbContext.Set<T>().Add(entity);
|
_dbContext.Set<T>().Add(entity);
|
||||||
@@ -80,24 +48,12 @@ namespace Microsoft.eShopWeb.Infrastructure.Data
|
|||||||
|
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update(T entity)
|
|
||||||
{
|
|
||||||
_dbContext.Entry(entity).State = EntityState.Modified;
|
|
||||||
_dbContext.SaveChanges();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task UpdateAsync(T entity)
|
public async Task UpdateAsync(T entity)
|
||||||
{
|
{
|
||||||
_dbContext.Entry(entity).State = EntityState.Modified;
|
_dbContext.Entry(entity).State = EntityState.Modified;
|
||||||
await _dbContext.SaveChangesAsync();
|
await _dbContext.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Delete(T entity)
|
|
||||||
{
|
|
||||||
_dbContext.Set<T>().Remove(entity);
|
|
||||||
_dbContext.SaveChanges();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task DeleteAsync(T entity)
|
public async Task DeleteAsync(T entity)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -14,10 +14,10 @@ namespace Microsoft.eShopWeb.Web.Services
|
|||||||
{
|
{
|
||||||
private readonly IAsyncRepository<Basket> _basketRepository;
|
private readonly IAsyncRepository<Basket> _basketRepository;
|
||||||
private readonly IUriComposer _uriComposer;
|
private readonly IUriComposer _uriComposer;
|
||||||
private readonly IRepository<CatalogItem> _itemRepository;
|
private readonly IAsyncRepository<CatalogItem> _itemRepository;
|
||||||
|
|
||||||
public BasketViewModelService(IAsyncRepository<Basket> basketRepository,
|
public BasketViewModelService(IAsyncRepository<Basket> basketRepository,
|
||||||
IRepository<CatalogItem> itemRepository,
|
IAsyncRepository<CatalogItem> itemRepository,
|
||||||
IUriComposer uriComposer)
|
IUriComposer uriComposer)
|
||||||
{
|
{
|
||||||
_basketRepository = basketRepository;
|
_basketRepository = basketRepository;
|
||||||
@@ -34,30 +34,15 @@ namespace Microsoft.eShopWeb.Web.Services
|
|||||||
{
|
{
|
||||||
return await CreateBasketForUser(userName);
|
return await CreateBasketForUser(userName);
|
||||||
}
|
}
|
||||||
return CreateViewModelFromBasket(basket);
|
return await CreateViewModelFromBasket(basket);
|
||||||
}
|
}
|
||||||
|
|
||||||
private BasketViewModel CreateViewModelFromBasket(Basket basket)
|
private async Task<BasketViewModel> CreateViewModelFromBasket(Basket basket)
|
||||||
{
|
{
|
||||||
var viewModel = new BasketViewModel();
|
var viewModel = new BasketViewModel();
|
||||||
viewModel.Id = basket.Id;
|
viewModel.Id = basket.Id;
|
||||||
viewModel.BuyerId = basket.BuyerId;
|
viewModel.BuyerId = basket.BuyerId;
|
||||||
viewModel.Items = basket.Items.Select(i =>
|
viewModel.Items = await GetBasketItems(basket.Items); ;
|
||||||
{
|
|
||||||
var itemModel = new BasketItemViewModel()
|
|
||||||
{
|
|
||||||
Id = i.Id,
|
|
||||||
UnitPrice = i.UnitPrice,
|
|
||||||
Quantity = i.Quantity,
|
|
||||||
CatalogItemId = i.CatalogItemId
|
|
||||||
|
|
||||||
};
|
|
||||||
var item = _itemRepository.GetById(i.CatalogItemId);
|
|
||||||
itemModel.PictureUrl = _uriComposer.ComposePicUri(item.PictureUri);
|
|
||||||
itemModel.ProductName = item.Name;
|
|
||||||
return itemModel;
|
|
||||||
})
|
|
||||||
.ToList();
|
|
||||||
return viewModel;
|
return viewModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,5 +58,26 @@ namespace Microsoft.eShopWeb.Web.Services
|
|||||||
Items = new List<BasketItemViewModel>()
|
Items = new List<BasketItemViewModel>()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<List<BasketItemViewModel>> GetBasketItems(IReadOnlyCollection<BasketItem> basketItems)
|
||||||
|
{
|
||||||
|
var items = new List<BasketItemViewModel>();
|
||||||
|
foreach (var item in basketItems)
|
||||||
|
{
|
||||||
|
var itemModel = new BasketItemViewModel
|
||||||
|
{
|
||||||
|
Id = item.Id,
|
||||||
|
UnitPrice = item.UnitPrice,
|
||||||
|
Quantity = item.Quantity,
|
||||||
|
CatalogItemId = item.CatalogItemId
|
||||||
|
};
|
||||||
|
var catalogItem = await _itemRepository.GetByIdAsync(item.CatalogItemId);
|
||||||
|
itemModel.PictureUrl = _uriComposer.ComposePicUri(catalogItem.PictureUri);
|
||||||
|
itemModel.ProductName = catalogItem.Name;
|
||||||
|
items.Add(itemModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,14 +18,14 @@ namespace Microsoft.eShopWeb.Web.Services
|
|||||||
public class CatalogService : ICatalogService
|
public class CatalogService : ICatalogService
|
||||||
{
|
{
|
||||||
private readonly ILogger<CatalogService> _logger;
|
private readonly ILogger<CatalogService> _logger;
|
||||||
private readonly IRepository<CatalogItem> _itemRepository;
|
private readonly IAsyncRepository<CatalogItem> _itemRepository;
|
||||||
private readonly IAsyncRepository<CatalogBrand> _brandRepository;
|
private readonly IAsyncRepository<CatalogBrand> _brandRepository;
|
||||||
private readonly IAsyncRepository<CatalogType> _typeRepository;
|
private readonly IAsyncRepository<CatalogType> _typeRepository;
|
||||||
private readonly IUriComposer _uriComposer;
|
private readonly IUriComposer _uriComposer;
|
||||||
|
|
||||||
public CatalogService(
|
public CatalogService(
|
||||||
ILoggerFactory loggerFactory,
|
ILoggerFactory loggerFactory,
|
||||||
IRepository<CatalogItem> itemRepository,
|
IAsyncRepository<CatalogItem> itemRepository,
|
||||||
IAsyncRepository<CatalogBrand> brandRepository,
|
IAsyncRepository<CatalogBrand> brandRepository,
|
||||||
IAsyncRepository<CatalogType> typeRepository,
|
IAsyncRepository<CatalogType> typeRepository,
|
||||||
IUriComposer uriComposer)
|
IUriComposer uriComposer)
|
||||||
@@ -46,13 +46,13 @@ namespace Microsoft.eShopWeb.Web.Services
|
|||||||
new CatalogFilterPaginatedSpecification(itemsPage * pageIndex, itemsPage, brandId, typeId);
|
new CatalogFilterPaginatedSpecification(itemsPage * pageIndex, itemsPage, brandId, typeId);
|
||||||
|
|
||||||
// the implementation below using ForEach and Count. We need a List.
|
// the implementation below using ForEach and Count. We need a List.
|
||||||
var itemsOnPage = _itemRepository.List(filterPaginatedSpecification).ToList();
|
var itemsOnPage = await _itemRepository.ListAsync(filterPaginatedSpecification);
|
||||||
var totalItems = _itemRepository.Count(filterSpecification);
|
var totalItems = await _itemRepository.CountAsync(filterSpecification);
|
||||||
|
|
||||||
itemsOnPage.ForEach(x =>
|
foreach (var itemOnPage in itemsOnPage)
|
||||||
{
|
{
|
||||||
x.PictureUri = _uriComposer.ComposePicUri(x.PictureUri);
|
itemOnPage.PictureUri = _uriComposer.ComposePicUri(itemOnPage.PictureUri);
|
||||||
});
|
}
|
||||||
|
|
||||||
var vm = new CatalogIndexViewModel()
|
var vm = new CatalogIndexViewModel()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -84,8 +84,7 @@ namespace Microsoft.eShopWeb.Web
|
|||||||
ConfigureCookieSettings(services);
|
ConfigureCookieSettings(services);
|
||||||
|
|
||||||
CreateIdentityIfNotCreated(services);
|
CreateIdentityIfNotCreated(services);
|
||||||
|
|
||||||
services.AddScoped(typeof(IRepository<>), typeof(EfRepository<>));
|
|
||||||
services.AddScoped(typeof(IAsyncRepository<>), typeof(EfRepository<>));
|
services.AddScoped(typeof(IAsyncRepository<>), typeof(EfRepository<>));
|
||||||
|
|
||||||
services.AddScoped<ICatalogService, CachedCatalogService>();
|
services.AddScoped<ICatalogService, CachedCatalogService>();
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ namespace Microsoft.eShopWeb.IntegrationTests.Repositories.BasketItemRepositoryT
|
|||||||
await _basketItemRepository.DeleteAsync(existingBasket.Items.FirstOrDefault());
|
await _basketItemRepository.DeleteAsync(existingBasket.Items.FirstOrDefault());
|
||||||
_catalogContext.SaveChanges();
|
_catalogContext.SaveChanges();
|
||||||
|
|
||||||
var basketFromDB = _basketRepository.GetById(BasketBuilder.BasketId);
|
var basketFromDB = await _basketRepository.GetByIdAsync(BasketBuilder.BasketId);
|
||||||
|
|
||||||
Assert.Equal(0, basketFromDB.Items.Count);
|
Assert.Equal(0, basketFromDB.Items.Count);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using System.Linq;
|
|||||||
using Microsoft.eShopWeb.UnitTests.Builders;
|
using Microsoft.eShopWeb.UnitTests.Builders;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
using Xunit.Abstractions;
|
using Xunit.Abstractions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Microsoft.eShopWeb.IntegrationTests.Repositories.OrderRepositoryTests
|
namespace Microsoft.eShopWeb.IntegrationTests.Repositories.OrderRepositoryTests
|
||||||
{
|
{
|
||||||
@@ -24,7 +25,7 @@ namespace Microsoft.eShopWeb.IntegrationTests.Repositories.OrderRepositoryTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void GetsExistingOrder()
|
public async Task GetsExistingOrder()
|
||||||
{
|
{
|
||||||
var existingOrder = OrderBuilder.WithDefaultValues();
|
var existingOrder = OrderBuilder.WithDefaultValues();
|
||||||
_catalogContext.Orders.Add(existingOrder);
|
_catalogContext.Orders.Add(existingOrder);
|
||||||
@@ -32,7 +33,7 @@ namespace Microsoft.eShopWeb.IntegrationTests.Repositories.OrderRepositoryTests
|
|||||||
int orderId = existingOrder.Id;
|
int orderId = existingOrder.Id;
|
||||||
_output.WriteLine($"OrderId: {orderId}");
|
_output.WriteLine($"OrderId: {orderId}");
|
||||||
|
|
||||||
var orderFromRepo = _orderRepository.GetById(orderId);
|
var orderFromRepo = await _orderRepository.GetByIdAsync(orderId);
|
||||||
Assert.Equal(OrderBuilder.TestBuyerId, orderFromRepo.BuyerId);
|
Assert.Equal(OrderBuilder.TestBuyerId, orderFromRepo.BuyerId);
|
||||||
|
|
||||||
// Note: Using InMemoryDatabase OrderItems is available. Will be null if using SQL DB.
|
// Note: Using InMemoryDatabase OrderItems is available. Will be null if using SQL DB.
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ namespace Microsoft.eShopWeb.UnitTests.ApplicationCore.Services.BasketServiceTes
|
|||||||
basket.AddItem(2, It.IsAny<decimal>(), It.IsAny<int>());
|
basket.AddItem(2, It.IsAny<decimal>(), It.IsAny<int>());
|
||||||
_mockBasketRepo.Setup(x => x.GetByIdAsync(It.IsAny<int>()))
|
_mockBasketRepo.Setup(x => x.GetByIdAsync(It.IsAny<int>()))
|
||||||
.ReturnsAsync(basket);
|
.ReturnsAsync(basket);
|
||||||
var basketService = new BasketService(_mockBasketRepo.Object, null, null, null, _mockBasketItemRepo.Object);
|
var basketService = new BasketService(_mockBasketRepo.Object, null, null, _mockBasketItemRepo.Object);
|
||||||
|
|
||||||
await basketService.DeleteBasketAsync(It.IsAny<int>());
|
await basketService.DeleteBasketAsync(It.IsAny<int>());
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ namespace Microsoft.eShopWeb.UnitTests.ApplicationCore.Services.BasketServiceTes
|
|||||||
[Fact]
|
[Fact]
|
||||||
public async void ThrowsGivenInvalidBasketId()
|
public async void ThrowsGivenInvalidBasketId()
|
||||||
{
|
{
|
||||||
var basketService = new BasketService(_mockBasketRepo.Object, null, null, null, null);
|
var basketService = new BasketService(_mockBasketRepo.Object, null, null, null);
|
||||||
|
|
||||||
await Assert.ThrowsAsync<BasketNotFoundException>(async () =>
|
await Assert.ThrowsAsync<BasketNotFoundException>(async () =>
|
||||||
await basketService.SetQuantities(_invalidId, new System.Collections.Generic.Dictionary<string, int>()));
|
await basketService.SetQuantities(_invalidId, new System.Collections.Generic.Dictionary<string, int>()));
|
||||||
@@ -30,7 +30,7 @@ namespace Microsoft.eShopWeb.UnitTests.ApplicationCore.Services.BasketServiceTes
|
|||||||
[Fact]
|
[Fact]
|
||||||
public async void ThrowsGivenNullQuantities()
|
public async void ThrowsGivenNullQuantities()
|
||||||
{
|
{
|
||||||
var basketService = new BasketService(null, null, null, null, null);
|
var basketService = new BasketService(null, null, null, null);
|
||||||
|
|
||||||
await Assert.ThrowsAsync<ArgumentNullException>(async () =>
|
await Assert.ThrowsAsync<ArgumentNullException>(async () =>
|
||||||
await basketService.SetQuantities(123, null));
|
await basketService.SetQuantities(123, null));
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace Microsoft.eShopWeb.UnitTests.ApplicationCore.Services.BasketServiceTes
|
|||||||
[Fact]
|
[Fact]
|
||||||
public async void ThrowsGivenNullAnonymousId()
|
public async void ThrowsGivenNullAnonymousId()
|
||||||
{
|
{
|
||||||
var basketService = new BasketService(null, null, null, null, null);
|
var basketService = new BasketService(null, null, null, null);
|
||||||
|
|
||||||
await Assert.ThrowsAsync<ArgumentNullException>(async () => await basketService.TransferBasketAsync(null, "steve"));
|
await Assert.ThrowsAsync<ArgumentNullException>(async () => await basketService.TransferBasketAsync(null, "steve"));
|
||||||
}
|
}
|
||||||
@@ -17,7 +17,7 @@ namespace Microsoft.eShopWeb.UnitTests.ApplicationCore.Services.BasketServiceTes
|
|||||||
[Fact]
|
[Fact]
|
||||||
public async void ThrowsGivenNullUserId()
|
public async void ThrowsGivenNullUserId()
|
||||||
{
|
{
|
||||||
var basketService = new BasketService(null, null, null, null, null);
|
var basketService = new BasketService(null, null, null, null);
|
||||||
|
|
||||||
await Assert.ThrowsAsync<ArgumentNullException>(async () => await basketService.TransferBasketAsync("abcdefg", null));
|
await Assert.ThrowsAsync<ArgumentNullException>(async () => await basketService.TransferBasketAsync("abcdefg", null));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user