Filter/Search 使用多个字段 - ASP.NET MVC

Filter/Search using Multiple Fields - ASP.NET MVC

我正在使用 ASP.NET MVCEF 6.

我有一个库存页面,其中显示了库存商品的所有信息。现在我也想过滤记录。

在下图中,我有 3 个选项。我可能会按每个选项进行过滤,一次一个,或者两个或所有三个的组合。

我正在考虑为每个选项编写 linq 查询 selected。但如果过滤器选项 increases.Is 有任何更好的方法,这将是不可能的。

谢谢!

这是我在我的控制器中所做的。(当前下拉菜单有两个选项,不包括:“-- select 一个--”)

public ActionResult StockLevel(string option, string batch, string name)
{
    if (option != "0" && batch == "" && name == "")
    {
        if(option == "BelowMin")
        {
            List<Stock> stk = (from s in db.Stocks
                               where s.Qty < s.Item.AlertQty
                               select s).ToList();
            return View(stk);
        }
        else
        {
            List<Stock> stk = (from s in db.Stocks
                               where s.Qty == s.InitialQty
                               select s).ToList();
            return View(stk);
        }
    }
    if (option == "0" && batch != "" && name == "")
    {
        List<Stock> stk = (from s in db.Stocks
                           where s.BatchNo == batch
                           select s).ToList();
        return View(stk);
    }
    if (option == "0" && batch == "" && name != "")
    {
        List<Stock> stk = (from s in db.Stocks
                           where s.Item.Name.StartsWith(""+name+"")
                           select s).ToList();
        return View(stk);
    }
    return View(db.Stocks.ToList());
}

条件过滤

.ToList().First().Count() 和其他一些方法执行最终的 LINQ 查询。但在执行之前,您可以像这样应用过滤器:

var stocks = context.Stocks.AsQueryable();
if (batchNumber != null) stocks = stocks.Where(s => s.Number = batchNumber);
if (name != null)        stocks = stocks.Where(s => s.Name.StartsWith(name));
var result = stocks.ToList(); // execute query

WhereIf LINQ 扩展

简单 WhereIf 可以显着简化代码:

var result = db.Stocks
    .WhereIf(batchNumber != null, s => s.Number == batchNumber)
    .WhereIf(name != null,        s => s.Name.StartsWith(name))       
    .ToList();

WhereIf 实现。这是 IQueryable:

的简单扩展方法
public static class CollectionExtensions
{
    public static IQueryable<TSource> WhereIf<TSource>(
        this IQueryable<TSource> source,
        bool condition,
        Expression<Func<TSource, bool>> predicate)
    {
        if (condition)
            return source.Where(predicate);
        else
            return source;
    }
}

非 WhereIf LINQ 方式(推荐)

WhereIf 提供了更多的声明方式,如果你不想使用扩展,你可以像这样过滤:

var result = context.Stocks
    .Where(batchNumber == null || stock.Number == batchNumber)
    .Where(name == null || s => s.Name.StartsWith(name))
    .ToList();

它提供与 WhereIf 完全相同的效果,而且运行速度更快,因为运行时只需要构建一个 ExpressionTree,而不是构建多棵树并合并它们。

我建议您分离关注点并使用一种方法,使您的控制器中的代码像这样,简单、美观且可扩展:

public ActionResult Index(ProductSearchModel searchModel)
{
    var business = new ProductBusinessLogic();
    var model = business.GetProducts(searchModel);
    return View(model);
}

好处:

  • 您可以根据自己的需要在 ProductSearchModel 中添加任何内容。
  • 您可以根据需要在GetProducts中编写任何逻辑。没有限制。
  • 如果您添加新的搜索字段或选项,您的操作和控制器将保持不变。
  • 如果您的搜索逻辑发生变化,您的操作和控制器将保持不变。
  • 您可以在需要搜索产品的任何地方、在控制器中甚至在其他业务逻辑中重用搜索逻辑。
  • 有了这样的 ProductSearchModel,您可以将其用作 ProductSearch 部分视图的模型,您可以将 DataAnnotations 应用于它以增强模型验证并帮助 UI使用 Display 或其他属性呈现它。
  • 您可以在该业务逻辑中添加与您的产品相关的其他业务逻辑class。
  • 按照这种方式,您可以获得更有条理的应用程序。

示例实现:

假设你有一个 Product class:

public class Product
{
    public int Id { get; set; }
    public int Price { get; set; }
    public string Name { get; set; }
}

您可以创建一个ProductSearchModel class 并根据它们放置一些您要搜索的字段:

public class ProductSearchModel
{
    public int? Id { get; set; }
    public int? PriceFrom { get; set; }
    public int? PriceTo { get; set; }
    public string Name { get; set; }
}

然后你可以这样把你的搜索逻辑放在ProductBusinessLogicclass中:

public class ProductBusinessLogic
{
    private YourDbContext Context;
    public ProductBusinessLogic()
    {
        Context = new YourDbContext();
    }

    public IQueryable<Product> GetProducts(ProductSearchModel searchModel)
    {
        var result = Context.Products.AsQueryable();
        if (searchModel != null)
        {
            if (searchModel.Id.HasValue)
                result = result.Where(x => x.Id == searchModel.Id);
            if (!string.IsNullOrEmpty(searchModel.Name))
                result = result.Where(x => x.Name.Contains(searchModel.Name));
            if (searchModel.PriceFrom.HasValue)
                result = result.Where(x => x.Price >= searchModel.PriceFrom);
            if (searchModel.PriceTo.HasValue)
                result = result.Where(x => x.Price <= searchModel.PriceTo);
        }
        return result;     
    }
}

那么在你的ProductController中你可以这样使用:

public ActionResult Index(ProductSearchModel searchModel)
{
    var business = new ProductBusinessLogic();
    var model = business.GetProducts(searchModel);
    return View(model);
}

重要提示:

在实际实施中,请考虑为您的业务实施合适的 Dispose 模式 class 以在需要时处理数据库上下文。有关详细信息,请查看 Implementing a Dispose method or Dispose Pattern.

public ActionResult Index(string searchid)
{ 
var personTables = db.PersonTables.Where(o => o.Name.StartsWith(searchid) )||  o.CombanyTable.ComName.StartsWith(searchid) ).Include(k => k.CombanyTable);
return View(personTables.ToList());
}

我已经编写了一些扩展来使这更容易。 https://www.nuget.org/packages/LinqConditionalExtensions/

这不是重新发明轮子。一些扩展已经被推荐。您可以按如下方式重写您的逻辑。

var results = db.Stocks
                .If(option != "0", stocks => stocks
                    .IfChain(option == "BelowMin", optionStocks => optionStocks
                        .Where(stock => stock.Qty < stock.Item.AlertQty))
                    .Else(optionStocks => optionStocks
                        .Where(stock => stock.Qty == stock.InitialQty)))
                .WhereIf(!string.IsNullOrWhiteSpace(batch), stock => stock.BatchNo == batch)
                .WhereIf(!string.IsNullOrWhiteSpace(name), stock => stock.Item.Name.StartsWith("" + name + ""))
                .ToList();

return results;

基本上,如果条件为真,初始 If() 方法将应用传递的 if 链。 IfChain() 是嵌套的 if-else 语句。 IfChain() 允许您链接多个 IfElse() 并以 Else() 结尾。

如果条件为真,WhereIf() 将有条件地应用您的 where 子句。

如果您对该库感兴趣,https://github.com/xKloc/LinqConditionalExtensions 有自述文件。