Filter/Search 使用多个字段 - ASP.NET MVC
Filter/Search using Multiple Fields - ASP.NET MVC
我正在使用 ASP.NET MVC 和 EF 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; }
}
然后你可以这样把你的搜索逻辑放在ProductBusinessLogic
class中:
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 有自述文件。
我正在使用 ASP.NET MVC 和 EF 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; }
}
然后你可以这样把你的搜索逻辑放在ProductBusinessLogic
class中:
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 有自述文件。