使用多个字段过滤/搜索 - ASP.NET MVC

Posted

技术标签:

【中文标题】使用多个字段过滤/搜索 - ASP.NET MVC【英文标题】:Filter/Search using Multiple Fields - ASP.NET MVC 【发布时间】:2015-10-15 16:36:18 【问题描述】:

我正在使用 ASP.NET MVCEF 6

我有一个股票页面,其中显示了有关股票项目的所有信息。现在我也想过滤记录。

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

我正在考虑为每个选择的选项编写 linq 查询。但是如果过滤器选项增加,这将是不可能的。有没有更好的方法。

谢谢!

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

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

【问题讨论】:

您是否已经尝试过任何代码? 是的,刚刚为这三个选项中的每一个都写了查询。但我没有写多个选项,因为我认为这不是好方法。 @Avi-B 我建议在这种情况下使用SearchModel,如果您对这种方法感兴趣,请告诉我,我会为您发布答案。 您可以使用谓词,但在这种情况下,最好的办法是使用表达式树在填写表单元素时动态创建搜索查询。 使用 !string.IsNullOrWhiteSpace(batch) 而不是 batch == "" 【参考方案1】:

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

public ActionResult Index(ProductSearchModel searchModel)

    var business = new ProductBusinessLogic();
    var model = business.GetProducts(searchModel);
    return View(model);

好处:

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

示例实现:

假设你有一个Product 类:

public class Product

    public int Id  get; set; 
    public int Price  get; set; 
    public string Name  get; set; 

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

public class ProductSearchModel

    public int? Id  get; set; 
    public int? PriceFrom  get; set; 
    public int? PriceTo  get; set; 
    public string Name  get; set; 

然后你可以把你的搜索逻辑放在ProductBusinessLogic类中:

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 模式,以便在需要时处理数据库上下文。如需更多信息,请查看Implementing a Dispose method 或Dispose Pattern。

【讨论】:

我正在使用您的想法,并且在我搜索时效果很好,但是当我尝试对数据进行排序时,搜索条件丢失了。我的操作看起来像这样public ActionResult Index(string sortOrder, SearchTransacModel searchModel, SearchTransacModel currentFilter, int? page) 我将搜索模型传递给这样的视图,以保留我的搜索参数`ViewBag.currentFilter = searchModel;` GetProducts 方法的结果是IQueryable&lt;Product&gt;,您可以简单地对结果应用排序和分页。将合适的排序列名称、排序顺序和页码传递给操作并使用它们就足够了。 在渲染分页链接和负责排序的列标题时,您应该在链接中添加合适的查询字符串以正确操作。在我的项目中,这是我的Grid helper/component 的责任。 @KayGee 最好在这篇文章的启发下提出一个新问题,让社区帮助你。另外,如果您通知我,我当然也会看看您的问题:) ModelBinder 查看动作参数,因为它看到动作有一个ProductSearchModel 类型的参数,所以创建它的一个实例。然后查看查询字符串或表单参数,检查是否为Id 属性(不区分大小写)发布了值,然后初始化对象的Id 属性,Name 属性和其他属性相同。如需更多信息,请搜索ASP.NET MVC 中的模型绑定,并阅读this one 等几篇文章。【参考方案2】:

条件过滤

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

Non-WhereIf LINQ 方式(推荐)

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

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

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

【讨论】:

好吧,我对 asp.net mvc 和边做边学真的很陌生。我会看一下 int 表达式,看看它是否适合我。谢谢。 使用 WhereIf 的好方法 在 BaseController 中使用它我需要在返回源添加 .AsQueryable.Where(predicate).AsQueryable(); 您推荐的 Non-WhereIf LINQ 方式不是很好!问题是,如果您在数据库上使用它,则会在 SQL 查询中生成空检查。 谓词在扩展方法中应该是 Expression> 而不是 Func【参考方案3】:

我编写了一些扩展来简化此操作。 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 有自述文件。

【讨论】:

【参考方案4】:
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());

【讨论】:

添加解决方案的描述。

以上是关于使用多个字段过滤/搜索 - ASP.NET MVC的主要内容,如果未能解决你的问题,请参考以下文章

使用 C# 在 ASP.NET MVC 中使用多个参数过滤数据

使用 asp.net mvc 搜索两列字段

在 asp.net MVC 中使用多过滤器数据表

ASP.Net MVC开发基础学习笔记:四校验AJAX与过滤器

使用 2 个表实现 ASP.NET MVC5 搜索功能

ASP.NET MVC 中相同模型数据的多个输入字段