web-dev-qa-db-fra.com

Filtrer/rechercher à l'aide de plusieurs champs - ASP.NET MVC

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!

 enter image description here

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());
}
31
Avi-B

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:

  • Vous pouvez mettre tout ce dont vous avez besoin dans votre ProductSearchModel en fonction de vos besoins.
  • Vous pouvez écrire n'importe quelle logique dans GetProducts en fonction des besoins. Il n'y a pas de limitation.
  • Si vous ajoutez un nouveau champ ou une nouvelle option de recherche, votre action et votre contrôleur resteront inchangés.
  • Si la logique de votre recherche change, votre action et votre contrôleur resteront inchangés.
  • Vous pouvez réutiliser la logique de recherche chaque fois que vous en avez besoin pour rechercher des produits, des contrôleurs ou même une autre logique métier.
  • Ayant une telle variable 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.
  • Vous pouvez ajouter une autre logique métier liée à votre produit dans cette classe de logique métier.
  • De cette façon, vous pouvez avoir une application plus organisée.

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 .

67
Reza Aghaei

Filtrage conditionnel

.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

Où Extension LINQ

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

Méthode LINQ non recommandée (recommandé)

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.

12
Andrei

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.

0
Todd Skelton
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());
}
0
ana