Merge pull request #221 from dotnet-architecture/remove-irepository

Removing IRepository in favor of IAsyncRepository
This commit is contained in:
Eric Fleming
2019-03-09 18:59:14 -05:00
committed by GitHub
11 changed files with 46 additions and 104 deletions

View File

@@ -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);
}
}

View File

@@ -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;
} }

View File

@@ -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;
@@ -21,58 +21,26 @@ 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);
@@ -81,24 +49,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)
{ {
_dbContext.Set<T>().Remove(entity); _dbContext.Set<T>().Remove(entity);

View File

@@ -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;
}
} }
} }

View File

@@ -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()
{ {

View File

@@ -85,7 +85,6 @@ namespace Microsoft.eShopWeb.Web
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>();

View File

@@ -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);
} }

View File

@@ -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.

View File

@@ -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>());

View File

@@ -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));

View File

@@ -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));
} }