Requêtes Linq Conditionnelles
on travaille sur une visionneuse de journaux. L'utilisation aura l'option de filtrer par utilisateur, gravité,etc. Dans les jours Sql j'ajouterais à la chaîne de requête, mais je veux le faire avec Linq. Comment puis-je ajouter des clauses où?
12 réponses
si vous voulez filtrer seulement si certains critères sont respectés, faites quelque chose comme ça
var logs = from log in context.Logs
select log;
if (filterBySeverity)
logs = logs.Where(p => p.Severity == severity);
if (filterByUser)
logs = logs.Where(p => p.User == user);
faire ainsi permettra à votre arbre D'Expression d'être exactement ce que vous voulez. De cette façon, le SQL créé sera exactement ce dont vous avez besoin et rien de moins.
si vous avez besoin de filtrer la base sur une Liste / Tableau utilisez ce qui suit:
public List<Data> GetData(List<string> Numbers, List<string> Letters)
{
if (Numbers == null)
Numbers = new List<string>();
if (Letters == null)
Letters = new List<string>();
var q = from d in database.table
where (Numbers.Count == 0 || Numbers.Contains(d.Number))
where (Letters.Count == 0 || Letters.Contains(d.Letter))
select new Data
{
Number = d.Number,
Letter = d.Letter,
};
return q.ToList();
}
j'ai fini par utiliser une réponse similaire à celle de Daren, mais avec une interface IQueryable:
IQueryable<Log> matches = m_Locator.Logs;
// Users filter
if (usersFilter)
matches = matches.Where(l => l.UserName == comboBoxUsers.Text);
// Severity filter
if (severityFilter)
matches = matches.Where(l => l.Severity == comboBoxSeverity.Text);
Logs = (from log in matches
orderby log.EventTime descending
select log).ToList();
qui construit la requête avant de frapper la base de données. La commande ne fonctionnera pas jusqu'à ce que .ToList() à la fin.
quand il s'agit de LINQ conditionnel, je suis très friand des filtres et des pipes.
http://blog.wekeroad.com/mvc-storefront/mvcstore-part-3 /
fondamentalement, vous créez une méthode d'extension pour chaque boîtier de filtre qui prend L'IQueryable et un paramètre.
public static IQueryable<Type> HasID(this IQueryable<Type> query, long? id)
{
return id.HasValue ? query.Where(o => i.ID.Equals(id.Value)) : query;
}
une autre option serait d'utiliser quelque chose comme le Prédicatebuilder discuté ici . Il vous permet d'écrire le code comme suit:
var newKids = Product.ContainsInDescription ("BlackBerry", "iPhone");
var classics = Product.ContainsInDescription ("Nokia", "Ericsson")
.And (Product.IsSelling());
var query = from p in Data.Products.Where (newKids.Or (classics))
select p;
notez que je n'ai que ça pour fonctionner avec Linq 2 SQL. Entitefram Framework ne met pas en œuvre L'Expression.Invoquer, ce qui est nécessaire pour que cette méthode fonctionne. J'ai une question concernant cette question ici .
:
bool lastNameSearch = true/false; // depending if they want to search by last name,
ayant ceci dans l'énoncé where
:
where (lastNameSearch && name.LastNameSearch == "smith")
signifie que lorsque la requête finale est créée, si lastNameSearch
est false
la requête omettra complètement N'importe quel SQL pour la recherche de nom de famille.
ce n'est pas la chose la plus jolie mais vous pouvez utiliser une expression lambda et passer vos conditions facultativement. Dans TSQL je fais beaucoup de ce qui suit pour rendre les paramètres optionnels:
où Field = @FieldVar ou @FieldVar est nul
vous pouvez dupliquer le même style avec la lambda suivante (un exemple de vérification de l'authentification):
MyDataContext db = new MyDataContext();
nul RunQuery(string param1, chaîne param2, int? param3) {
Func checkUser d'utilisateur = = >
((param1.Longueur > 0)? utilisateur.Param1 = = param1 : 1 == 1) &&
((param2.Longueur > 0)? utilisateur.Param2 = = param2 : 1 == 1) &&
((param3 != null)? utilisateur.Param3 = = param3 : 1 = = 1);
User foundUser = db.Utilisateur.SingleOrDefault (checkUser);
}
j'ai eu récemment une exigence semblable et j'ai finalement trouvé cela dans le MSDN. Csharp Samples for Visual Studio 2008
les classes incluses dans L'échantillon DynamicQuery du téléchargement vous permettent de créer des requêtes dynamiques à l'exécution dans le format suivant:
var query =
db.Customers.
Where("City = @0 and Orders.Count >= @1", "London", 10).
OrderBy("CompanyName").
Select("new(CompanyName as Name, Phone)");
en utilisant ceci vous pouvez construire une chaîne de requête dynamiquement à l'exécution et la passer dans la méthode où ():
string dynamicQueryString = "City = \"London\" and Order.Count >= 10";
var q = from c in db.Customers.Where(queryString, null)
orderby c.CompanyName
select c;
j'ai résolu cela avec une méthode d'extension pour permettre à LINQ d'être conditionnellement activé au milieu d'une expression fluide. Cela supprime la nécessité de casser l'expression avec les énoncés if
.
"151930920 l'extension de la méthode:
public static IQueryable<TSource> If<TSource>(
this IQueryable<TSource> source,
bool condition,
Func<IQueryable<TSource>, IQueryable<TSource>> branch)
{
return condition ? source : branch(source);
}
cela vous permet de faire ceci:
return context.Logs
.If(filterBySeverity, q => q.Where(p => p.Severity == severity))
.If(filterByUser, q => q.Where(p => p.User == user))
.ToList();
il suffit d'utiliser C#' & & de l'opérateur:
var items = dc.Users.Where(l => l.Date == DateTime.Today && l.Severity == "Critical")
Edit: Ah, faut lire plus attentivement. Vous voulais savoir comment conditionnellement ajouter des clauses supplémentaires. Dans ce cas, je n'ai aucune idée. :) Ce que je ferais probablement est juste préparer plusieurs requêtes, et exécuter la bonne, en fonction de ce que j'ai fini par avoir besoin.
vous pouvez utiliser une méthode externe:
var results =
from rec in GetSomeRecs()
where ConditionalCheck(rec)
select rec;
...
bool ConditionalCheck( typeofRec input ) {
...
}
cela fonctionnerait, mais ne peut pas être décomposé en arbres d'expression, ce qui signifie que Linq à SQL exécuterait le code de contrôle contre chaque enregistrement.
alternativement:
var results =
from rec in GetSomeRecs()
where
(!filterBySeverity || rec.Severity == severity) &&
(!filterByUser|| rec.User == user)
select rec;
qui pourrait fonctionner dans des arbres d'expression, ce qui signifie Linq à SQL serait optimisé.
Eh bien, ce que je pensais était que vous pourriez mettre les conditions de filtre dans une liste générique de prédicats:
var list = new List<string> { "me", "you", "meyou", "mow" };
var predicates = new List<Predicate<string>>();
predicates.Add(i => i.Contains("me"));
predicates.Add(i => i.EndsWith("w"));
var results = new List<string>();
foreach (var p in predicates)
results.AddRange(from i in list where p.Invoke(i) select i);
qui donne une liste contenant" me"," meyou", et"mow".
vous pourriez optimiser cela en faisant la foreach avec les prédicats dans une fonction totalement différente qui ORs tous les prédicats.