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;
}
(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.
Vous pouvez également utiliser PredicateBuilder de LinqKit pour chaîner plusieurs expressions lambda de typeafe à l'aide de Or ou Et.
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);
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); });
}
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);
}
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 ).
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();
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.
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:
Et des choses comme ça:
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.