c# - foreach 中的动态过滤(ASP.NET 和 EF)
问题描述
我有一个非常简单的案例,有一个控制器和一个存储库。
控制器:
[HttpGet]
public async Task<IActionResult> GetProductList(ProductQuery queryparams)
{
var products = await uow.ProductRepo.GetProductsWithQuery(queryparams);
var productsToReturn = mapper.Map<IEnumerable<ProductForListDto>>(products);
return Ok(productsToReturn);
}
存储库:
public async Task<AbstractPagedList<Product>>GetProductsWithQuery(ProductQuery qp)
{
var products = DorianContext.Products
.Include(p => p.Category)
.Include(p => p.PriceOffers)
.AsQueryable();
// if (filter.CategoryId.HasValue)
// products = products.Where(p => p.CategoryId == filter.CategoryId);
// if (filter.MinPrice.HasValue)
// products = products.Where(p => p.Price >= filter.MinPrice);
// if (filter.MaxPrice.HasValue)
// products = products.Where(p => p.Price <= filter.MaxPrice);
return await PagedList<Product>.CreateAsync(products, qp.PageNumber, qp.PageSize);
}
模型:
public class ProductQuery
{
public int? CategoryId { get; set; }
public decimal? MinPrice { get; set; }
public decimal? MaxPrice { get; set; }
}
代替无聊的注释部分,我们如何构建动态/通用逻辑来过滤 CategoryId、MinPrice 和 MaxPrice。(例如在 ProductQuery 的属性列表的 foreach 块中)
也许我们可以像下面这样使用字典对象和 foreach,但我不太确定如何从对象中获取属性名称作为字符串(我尝试使用 NewtonSoft.JObject 但没有成功)
var filterMap = new Dictionary<string, Expression<Func<Product, bool>>>()
{
["categoryId"] = (v => v.CategoryId == filter.CategoryId),
["collectionId"] = (v => v.ProductCollectionId == filter.CollectionId),
["minPrice"] = (v => v.Price >= filter.MinPrice),
["maxPrice"] = (v => v.Price <= filter.MaxPrice)
};
foreach (var key in filterMap)
{
products = products.Where(key.Value);
}
我不想使用反射。还赞赏具有此类案例最佳实践的想法或评论。
解决方案
我所做的工作是的,我可以像这样继续,但这会导致大量重复的逻辑。因为这是一个玩具项目,我正在寻找改进它的方法。这样一个项目,我同意这有点过头了。
因此,避免破坏 DRY 原则的最佳方法是在类中创建一个Filters
属性,ProductQuery
如下所示:
public class ProductQuery
{
public int? CategoryId { get; set; }
public decimal? MinPrice { get; set; }
public decimal? MaxPrice { get; set; }
public IEnumerable<Expression<Func<Product, bool>>> Filters
{
get
{
var filters = new List<Expression<Func<Product, bool>>>();
if (this.CategoryId.HasValue)
filters.Add(p => p.CategoryId == this.CategoryId);
if (this.MinPrice.HasValue)
filters.Add((p => p.Price >= this.MinPrice);
if (this.MaxPrice.HasValue)
filters.Add(p => p.Price <= this.MaxPrice);
return filters;
}
}
}
因此,在您的代码中,您可以像下面这样使用它:
public async Task<AbstractPagedList<Product>>GetProductsWithQuery(ProductQuery qp)
{
var products = DorianContext.Products
.Include(p => p.Category)
.Include(p => p.PriceOffers)
.AsQueryable();
foreach(var filter in qp.Filters)
{
products = products.Where(filter);
}
return await PagedList<Product>.CreateAsync(products, qp.PageNumber, qp.PageSize);
}
推荐阅读
- c# - 创建天蓝色搜索索引时无法识别 IsSearchable
- javascript - 获得不同的结果 Puppeteer 和 startsWith()
- ios - Apple Map 根据用户在 React-native-maps 中的半径变化缩小/缩小
- google-apps-script - 当从已部署公司的项目中调用 google script web app url 时,get java.io.IOException: Server returned HTTP response code: 403 for URL:
- javascript - 如何使用拼接根据javascript中的值从数组中删除对象
- excel - Excel 公式获得的价值刚好大于其他公式
- windows - Powershell (5.1) 安装模块或查找模块挂起/阻塞
- javascript - Jquery嵌套的li和ul标签没有点击
- angular - 在 Web Worker 中导入 tensorflow 时出现 Angular 打字稿类型检查问题
- ruby-on-rails - 创建新记录时忽略Rails模型默认值?