c# - foreach 中的动态过滤(ASP.NET 和 EF)

标签 c# entity-framework

我有一个非常简单的案例,带有 Controller 和存储库。

Controller :

    [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 block 中)

也许我们可以使用字典对象和 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);
        }

我不想使用反射。对于此类案例的最佳实践的想法或评论也将受到赞赏。

最佳答案

What I did works yes and I can continue just like this but this will result lots of duplicated logic. And because this is a toy project, I am searching for the ways to improve it. And such a project, this is overkill I agree..

因此,避免破坏 DRY 原则的最佳方法是在 ProductQuery 类中创建一个 Filters 属性,如下所示:

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# - foreach 中的动态过滤(ASP.NET 和 EF),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50333499/

相关文章:

c# - 编程对象建议

c# - 使用反射查看方法内部是否调用了方法

c# - 为什么 c# List 实现在 ensure capacity 方法中指定这个确切的值?

c# - Entity Framework : Many To Many Count and Sum

asp.net - EF6 等效于 EF Core 的 QueryTrackingBehavior.NoTracking

sql-server - 如何将 MS SQL 数据类型 numeric(19, 0) 映射到 .NET 类型

c# - 通过 POST 发送 XML 时,符号 & 转义了字符串的整个其余部分

c# - 捕获 USB 插拔事件 System.InvalidCastException

c# - "Object reference not set to an instance of an object error"添加具有 Entity Framework 多对多关系的项目时

c# - 无法将直接 SQL 查询的结果从通用列表转换为列表 <long>