web-dev-qa-db-fra.com

Clause WHERE dynamique dans LINQ

Quelle est la meilleure façon d'assembler une clause WHERE dynamique à une instruction LINQ?

J'ai plusieurs dizaines de cases à cocher sur un formulaire et je les renvoie en tant que: Dictionnaire <chaîne, Liste <chaîne>> (Dictionnaire <champNom, Liste <valeurs>>) à ma requête LINQ.

public IOrderedQueryable<ProductDetail> GetProductList(string productGroupName, string productTypeName, Dictionary<string,List<string>> filterDictionary)
{
    var q = from c in db.ProductDetail
            where c.ProductGroupName == productGroupName && c.ProductTypeName == productTypeName
            // insert dynamic filter here
            orderby c.ProductTypeName
            select c;
    return q;
}
52
Keith Barrows

alt text
(source: scottgu.com )

Vous avez besoin de quelque chose comme ça? Utilisez la bibliothèque de requêtes dynamiques Linq (le téléchargement inclut des exemples).

Consultez le blog de ScottG pour plus d'exemples.

52
Thomas Stock

Vous pouvez également utiliser PredicateBuilder de LinqKit pour chaîner plusieurs expressions lambda de typeafe à l'aide de Or ou Et.

http://www.albahari.com/nutshell/predicatebuilder.aspx

13
Linus

J'ai un scénario similaire où je dois ajouter des filtres basés sur l'entrée utilisateur et je chaîne la clause where.

Voici l exemple de code.

var votes = db.Votes.Where(r => r.SurveyID == surveyId);
if (fromDate != null)
{
    votes = votes.Where(r => r.VoteDate.Value >= fromDate);
}
if (toDate != null)
{
    votes = votes.Where(r => r.VoteDate.Value <= toDate);
}
votes = votes.Take(LimitRows).OrderByDescending(r => r.VoteDate);
12
Xavier John

Une approche simple peut être si vos colonnes sont de type simple comme String

public static IEnumerable<MyObject> WhereQuery(IEnumerable<MyObject> source, string columnName, string propertyValue)
{
   return source.Where(m => { return m.GetType().GetProperty(columnName).GetValue(m, null).ToString().StartsWith(propertyValue); });
}
8
Nitin Bourai

J'ai trouvé une solution que même moi, je peux comprendre ... en utilisant la méthode "Contient", vous pouvez enchaîner autant de WHERE que vous le souhaitez. Si le WHERE est une chaîne vide, il est ignoré (ou évalué comme tout sélectionner). Voici mon exemple de jointure de 2 tables dans LINQ, d'application de plusieurs clauses where et de remplissage d'une classe de modèle à renvoyer à la vue. (c'est un tout sélectionner).

public ActionResult Index()
    {
        string AssetGroupCode = "";
        string StatusCode = "";
        string SearchString = "";

        var mdl = from a in _db.Assets
                  join t in _db.Tags on a.ASSETID equals t.ASSETID
                  where a.ASSETGROUPCODE.Contains(AssetGroupCode)
                  && a.STATUSCODE.Contains(StatusCode)
                  && (
                  a.PO.Contains(SearchString)
                  || a.MODEL.Contains(SearchString)
                  || a.USERNAME.Contains(SearchString)
                  || a.LOCATION.Contains(SearchString)
                  || t.TAGNUMBER.Contains(SearchString)
                  || t.SERIALNUMBER.Contains(SearchString)
                  )
                  select new AssetListView
                  {
                      AssetId = a.ASSETID,
                      TagId = t.TAGID,
                      PO = a.PO,
                      Model = a.MODEL,
                      UserName = a.USERNAME,
                      Location = a.LOCATION,
                      Tag = t.TAGNUMBER,
                      SerialNum = t.SERIALNUMBER
                  };


        return View(mdl);
    }
5
mike

J'avais la même question ( filtre défini par l'utilisateur pour linq ), et @tvanfosson m'a parlé de Dynamic Linq ( http://code.msdn.Microsoft.com/csharpsamples ).

2
TcKs

Il semble beaucoup plus simple et plus simple d'utiliser l'opérateur ternaire pour décider dynamiquement si une condition est incluse

List productList = new List ();

        productList =
                db.ProductDetail.Where(p => p.ProductDetailID > 0 //Example prop
                && (String.IsNullOrEmpty(iproductGroupName) ? (true):(p.iproductGroupName.Equals(iproductGroupName)) ) //use ternary operator to make the condition dynamic
                && (ID == 0 ? (true) : (p.ID == IDParam))
                ).ToList();
1
Josué Camacho

Vous pouvez utiliser la méthode d'extension Any (). Ce qui suit semble fonctionner pour moi.

XStreamingElement root = new XStreamingElement("Results",
                from el in StreamProductItem(file)
                where fieldsToSearch.Any(s => el.Element(s) != null && el.Element(s).Value.Contains(searchTerm))
                select fieldsToReturn.Select(r => (r == "product") ? el : el.Element(r))
            );
            Console.WriteLine(root.ToString());

Où 'fieldsToSearch' et 'fieldsToReturn' sont tous deux des objets List.

1
Todd DeLand

Ce projet sur CodePlex a ce que vous voulez.

System.Linq.Dynamic - http://dynamiclinq.codeplex.com/

Description du projet

Étend System.Linq.Dynamic pour prendre en charge l'exécution d'expressions Lambda définies dans une chaîne par rapport à Entity Framework ou à tout fournisseur prenant en charge IQueryable.

Comme il s'agit d'une extension du code source que vous pouvez trouver sur Blog de Scott Guthrie cela vous permettra de faire des choses comme ceci:

enter image description here

Et des choses comme ça:

enter image description here

1
Zignd

C'est la solution que j'ai trouvée si quelqu'un est intéressé.

https://kellyschronicles.wordpress.com/2017/12/16/dynamic-predicate-for-a-linq-query/

Nous identifions d'abord le type d'élément unique que nous devons utiliser (Of TRow As DataRow), puis identifions la "source" que nous utilisons et lions l'identifiant à cette source ((source As TypedTableBase (Of TRow)). Ensuite, nous devons spécifier le prédicat ou la clause WHERE qui va être passée (prédicat As Func (Of TRow, Boolean)) qui sera retournée comme vraie ou fausse. Ensuite, nous identifions comment nous voulons que les informations retournées soient ordonnées (OrderByField As String). La fonction retournera alors un EnumerableRowCollection (Of TRow), notre collection de datarows qui ont rempli les conditions de notre prédicat (EnumerableRowCollection (Of TRow)). Ceci est un exemple de base. Bien sûr, vous devez vous assurer que votre champ de commande ne contient pas nulls, ou ont géré cette situation correctement et assurez-vous que les noms de vos colonnes (si vous utilisez une source de données fortement typée ne vous occupez pas de cela, il renommera les colonnes pour vous) sont standard.

1
KJM