J'utilise ASP.NET MVC avec EF 6.
J'ai une page de stock qui affiche toutes les informations sur les articles en stock. Maintenant, je veux aussi filtrer les enregistrements.
Dans l'image ci-dessous, j'ai 3 options. Je pourrais filtrer par chaque option, une à la fois ou par combinaison de deux ou avec les trois.
Je pensais écrire une requête linq pour chacune des options sélectionnées. Mais cela ne serait pas possible si l'option de filtre augmentait. Il existe un meilleur moyen d'y parvenir.
Merci!
C’est ce que j’ai fait dans mon contrôleur. (Le menu déroulant a actuellement deux options, à l’exclusion:
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());
}
Je vous recommande de séparer les préoccupations et d’utiliser une approche selon laquelle le code de votre contrôleur sera comme ceci: simple, beau et extensible:
public ActionResult Index(ProductSearchModel searchModel)
{
var business = new ProductBusinessLogic();
var model = business.GetProducts(searchModel);
return View(model);
}
Avantages:
ProductSearchModel
en fonction de vos besoins.GetProducts
en fonction des besoins. Il n'y a pas de limitation.ProductSearchModel
, vous pouvez l'utiliser comme modèle de la vue partielle ProductSearch
et vous pouvez lui appliquer DataAnnotations
pour améliorer la validation du modèle et aider l'interface utilisateur à la restituer à l'aide de Display
ou d'autres attributs.Exemple d'implémentation:
Supposons que vous ayez une classe Product
:
public class Product
{
public int Id { get; set; }
public int Price { get; set; }
public string Name { get; set; }
}
Vous pouvez créer une classe ProductSearchModel
et définir les champs que vous souhaitez rechercher en fonction de ceux-ci:
public class ProductSearchModel
{
public int? Id { get; set; }
public int? PriceFrom { get; set; }
public int? PriceTo { get; set; }
public string Name { get; set; }
}
Ensuite, vous pouvez mettre votre logique de recherche dans la classe ProductBusinessLogic
de cette façon:
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;
}
}
Ensuite, dans votre ProductController
, vous pouvez utiliser cette méthode:
public ActionResult Index(ProductSearchModel searchModel)
{
var business = new ProductBusinessLogic();
var model = business.GetProducts(searchModel);
return View(model);
}
Note importante:
Dans une implémentation réelle, envisagez de mettre en œuvre un modèle Dispose
approprié pour que votre classe affaires supprime le contexte de la base de données en cas de besoin. Pour plus d'informations, consultez Implémentation d'une méthode Dispose ou Dispose Pattern .
.ToList()
, .First()
, .Count()
et quelques autres méthodes exécutent la requête LINQ finale. Mais avant qu'il ne soit exécuté, vous pouvez appliquer des filtres comme cela:
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
simple peut considérablement simplifier le code:
var result = db.Stocks
.WhereIf(batchNumber != null, s => s.Number == batchNumber)
.WhereIf(name != null, s => s.Name.StartsWith(name))
.ToList();
WhereIf mise en œuvre. C'est une méthode d'extension simple pour IQueryable
:
public static class CollectionExtensions
{
public static IQueryable<TSource> WhereIf<TSource>(
this IQueryable<TSource> source,
bool condition,
Func<TSource, bool> predicate)
{
if (condition)
return source.Where(predicate).AsQueryable();
else
return source;
}
}
WhereIf
fournit plus de manière déclarative, si vous ne voulez pas utiliser d'extensions vous pouvez simplement filtrer comme ceci:
var result = context.Stocks
.Where(batchNumber == null || stock.Number == batchNumber)
.Where(name == null || s => s.Name.StartsWith(name))
.ToList();
Cela donne exactement le même effet que WhereIf
et fonctionnera plus rapidement car le moteur d’exécution n’aura besoin que de créer un seul ExpressionTree au lieu de créer plusieurs arbres et de les fusionner.
J'ai écrit quelques extensions pour rendre cela plus facile. https://www.nuget.org/packages/LinqConditionalExtensions/
Ce n'est pas réinventer la roue. Certaines des extensions ont déjà été recommandées. Vous pouvez réécrire votre logique comme suit.
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;
Fondamentalement, la méthode initiale If()
appliquera la chaîne if passée si la condition est vraie. La IfChain()
est votre instruction if-else imbriquée. IfChain()
vous permet de chaîner plusieurs IfElse()
et de terminer par Else()
.
La WhereIf()
n'appliquera que conditionnellement votre clause where si la condition est vraie.
Si vous êtes intéressé par la bibliothèque, https://github.com/xKloc/LinqConditionalExtensions a un fichier Lisez-moi.
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());
}