LINQ 查询异步/等待评审



我正在将一个工作的linq管道升级到异步,我在synthaxe/逻辑方面有点挣扎(在哪里task.run,async/await,Tolist......(。 目前它不会编译,因为最后一个方法返回 IEnumerable of Task 产品而不是 IEnumerable of product

这是电话:

public async Task<IEnumerable<ProductDto>> GetProducts(bool isLogged)
{
return await _mapper.GetStripeProductsDto(isLogged, false);
}

其中一个存储库:

public async Task<IEnumerable<StripeProduct>> GetAllStripeProductsAsync()
{
return (await _productService.ListAsync())
.Where(x => x.Type == "good" && x.Active == true);
}

以及我在哪里建立我的 DTO 并正在努力:

public async Task<IEnumerable<ProductDto>> GetStripeProductsDto(bool isLogged, bool isSubscriber)
{
var productList = (await _productRepo.GetAllStripeProductsAsync()).ToList();
return await Task.Run(async () => 
GetSkuOffers(productList)
.Concat(await GetSubsciptionOffers(productList))
.GroupBy(product => product.Name)
.Select(productGroup => new ProductDto
{
Name = productGroup.Key,
Id = productGroup.Select(product => product.Id).First(),
Description = productGroup.Select(product => product.Description).First(),
Image = productGroup.Select(product => product.Image).First(),
CurrentUserProfile = isSubscriber
? OfferTypeEnum.Pro.ToString()
: isLogged
? OfferTypeEnum.Registered.ToString()
: OfferTypeEnum.Basic.ToString(),
Prices = productGroup.Select(product => new
{
Offer = product.OfferType.ToString(),
Price = product.Price.ToString()
})
.ToDictionary(p => p.Offer, p => p.Price)
})
.ToList())
.ConfigureAwait(false);
}
private IEnumerable<Product> GetSkuOffers(IEnumerable<StripeProduct> productList)
{
return productList
.SelectMany(sku => sku.Skus.Data, (product, sku) => new Product
{
Name = product.Name,
Id = product.Id,
Image = new Uri(product.Images.First()),
Description = product.Description,
OfferType = sku.Id.Contains("Basic") ? OfferTypeEnum.Basic : OfferTypeEnum.Registered,
Price = sku.Price
});
}
private IEnumerable<Product> GetSubsciptionOffers(IEnumerable<StripeProduct> productList)
{
return 
productList
.Select(async product => new Product
{
Name = product.Name,
Id = product.Id,
Image = new Uri(product.Images.First()),
Description = product.Description,
OfferType = OfferTypeEnum.Pro,
Price = (await _planRepo.GetPlanByIdAsync(product.Metadata.First().Value)).Amount.GetValueOrDefault()
});
}

编辑:编译版本,ToListAsync 似乎仅适用于数据库,我的存储库调用 api,所以我放弃了;我删除了 Task.Run(...(,并以可能令人讨厌的方式摆脱了 IEnumerable 的任务产品

public async Task<IEnumerable<ProductDto>> GetStripeProductsDto(bool isLogged, bool isSubscriber)
{
var productList = (await _productRepo.GetAllStripeProductsAsync()).ToList();
var skuOffers = GetSkuOffers(productList);
var subsciptionOffers = GetSubsciptionOffers(productList);
return skuOffers
.Concat(subsciptionOffers)
.GroupBy(product => product.Name)
.Select(productGroup => new ProductDto
{
Name = productGroup.Key,
Id = productGroup.Select(product => product.Id).First(),
Description = productGroup.Select(product => product.Description).First(),
Image = productGroup.Select(product => product.Image).First(),
CurrentUserProfile = isSubscriber
? OfferTypeEnum.Pro.ToString()
: isLogged
? OfferTypeEnum.Registered.ToString()
: OfferTypeEnum.Basic.ToString(),
Prices = productGroup.Select(product => new
{
Offer = product.OfferType.ToString(),
Price = product.Price.ToString()
})
.ToDictionary(p => p.Offer, p => p.Price)
})
.ToList();
}
private IEnumerable<Product> GetSkuOffers(IEnumerable<StripeProduct> productList)
{
return productList
.SelectMany(sku => sku.Skus.Data, (product, sku) => new Product
{
Name = product.Name,
Id = product.Id,
Image = new Uri(product.Images.First()),
Description = product.Description,
OfferType = sku.Id.Contains("Basic") ? OfferTypeEnum.Basic : OfferTypeEnum.Registered,
Price = sku.Price
});
}
private IEnumerable<Product> GetSubsciptionOffers(IEnumerable<StripeProduct> productList)
{
return productList
.Select(product => new Product
{
Name = product.Name,
Id = product.Id,
Image = new Uri(product.Images.First()),
Description = product.Description,
OfferType = OfferTypeEnum.Pro,
//Price = _planRepo.GetPlanById(product.Metadata.First().Value).Amount.GetValueOrDefault()
Price = GetSubscriptionPrice(product.Metadata.First().Value)
}).ToList();
}
private int GetSubscriptionPrice(string str)
{
var plan = Task.Run(() => _planRepo.GetPlanByIdAsync(str)).GetAwaiter().GetResult();
return plan.Amount.GetValueOrDefault();
}

我会做这样的事情:

public async Task<IEnumerable<ProductDto>> GetProductsAsync(bool isLogged)
{
return await _mapper.GetStripeProductsDto(isLogged, false);
}
public async Task<IEnumerable<StripeProduct>> GetAllStripeProductsAsync()
{
var list = await _productService.ListAsync();
return await list.Where(x => x.Type == "good" && x.Active == true).ToListAsync();
}
public async Task<IEnumerable<ProductDto>> GetStripeProductsDtoAsync(bool isLogged, bool isSubscriber)
{
// here you're making async call and when task is done, you are making .ToList() on results
var productList = await _productRepo.GetAllStripeProductsAsync();
// this will be executed when productList has results from database (task).
// Because GetSkuOffers() method is sync you can execute this like below.
var skuOffersResult = GetSkuOffers(productList);
// get asynchronously subscription offers
var getSubscriptionOffers = await GetSubsciptionOffers(productList);
// this is done also synchronously so you don't need to use async/await statements
skuOffersResult.Concat(getSubscriptionOffers)
.GroupBy(product => product.Name)
.Select(productGroup => new ProductDto
{
Name = productGroup.Key,
Id = productGroup.Select(product => product.Id).First(),
Description = productGroup.Select(product => product.Description).First(),
Image = productGroup.Select(product => product.Image).First(),
CurrentUserProfile = isSubscriber
? OfferTypeEnum.Pro.ToString()
: isLogged
? OfferTypeEnum.Registered.ToString()
: OfferTypeEnum.Basic.ToString(),
Prices = productGroup.Select(product => new
{
Offer = product.OfferType.ToString(),
Price = product.Price.ToString()
})
.ToDictionary(p => p.Offer, p => p.Price)
})
.ToList());
}
private IEnumerable<Product> GetSkuOffers(IEnumerable<StripeProduct> productList)
{
return productList
.SelectMany(sku => sku.Skus.Data, (product, sku) => new Product
{
Name = product.Name,
Id = product.Id,
Image = new Uri(product.Images.First()),
Description = product.Description,
OfferType = sku.Id.Contains("Basic") ? OfferTypeEnum.Basic : OfferTypeEnum.Registered,
Price = sku.Price
});
}
private async Task<IEnumerable<Product>> GetSubsciptionOffers(IEnumerable<StripeProduct> productList)
{
return
productList
.Select(async product => new Product
{
Name = product.Name,
Id = product.Id,
Image = new Uri(product.Images.First()),
Description = product.Description,
OfferType = OfferTypeEnum.Pro,
Price = (await _planRepo.GetPlanByIdAsync(product.Metadata.First().Value)).Amount.GetValueOrDefault()
});
}

如何使用 async/await 的简单示例: 假设您有使用存储库来获取产品列表的服务 - 现在所有服务都是同步制作的:

public class Repository : IRepository
{
public List<Product> GetProducts()
{
return _dbContext.Products.ToList();
}
}
public class Service : IService
{
private readonly IRepository _repository;
public Service(IRepository repository)
{
_repository = repository;
}
public List<Product> GetProductsFromDb()
{
return _repository.GetProducts();
}
}

现在,您要更改此代码以使其异步工作:

public class Repository : IRepository
{
public async Task<List<Product>> GetProductsAsync()
{
return await _dbContext.Products.ToListAsync();
}
}
public class Service : IService
{
private readonly IRepository _repository;
public Service(IRepository repository)
{
_repository = repository;
}
public async Task<List<Product>> GetProductsFromDbAsync()
{
return await _repository.GetProductsAsync();
}
}

最新更新