Query Linq condizionali

Stiamo lavorando su un Log Viewer. L’uso avrà la possibilità di filtrare per utente, gravità, ecc. Nei giorni Sql aggiungerei alla stringa di query, ma voglio farlo con Linq. Come posso aggiungere condizionalmente clausole in cui?

se vuoi filtrare solo se vengono superati determinati criteri, fai qualcosa di simile

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

In questo modo, il tuo albero di espressione sarà esattamente quello che desideri. In questo modo l’SQL creato sarà esattamente ciò di cui hai bisogno e niente di meno.

Se è necessario filtrare la base su un elenco / array, utilizzare quanto segue:

  public List GetData(List Numbers, List Letters) { if (Numbers == null) Numbers = new List(); if (Letters == null) Letters = new List(); 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(); } 

Ho finito di usare una risposta simile a quella di Daren, ma con un’interfaccia IQueryable:

 IQueryable 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(); 

Questo costruisce la query prima di colpire il database. Il comando non verrà eseguito fino a .ToList () alla fine.

Quando si tratta di linq condizionale, mi piace molto il pattern di filtri e tubi.
http://blog.wekeroad.com/mvc-storefront/mvcstore-part-3/

Fondamentalmente si crea un metodo di estensione per ciascun caso di filtro che include IQueryable e un parametro.

 public static IQueryable HasID(this IQueryable query, long? id) { return id.HasValue ? query.Where(o => i.ID.Equals(id.Value)) : query; } 

Un’altra opzione sarebbe quella di utilizzare qualcosa come il PredicateBuilder discusso qui . Ti permette di scrivere codice come il seguente:

 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; 

Nota che ho solo questo per funzionare con Linq 2 SQL. EntityFramework non implementa Expression.Invoke, che è necessario affinché questo metodo funzioni. Ho una domanda riguardo a questo problema qui .

Facendo questo:

 bool lastNameSearch = true/false; // depending if they want to search by last name, 

avendo questo nella dichiarazione in where :

 where (lastNameSearch && name.LastNameSearch == "smith") 

significa che quando viene creata la query finale, se lastNameSearch è false la query ometterà completamente qualsiasi SQL per la ricerca del cognome.

Non è la cosa più bella ma puoi usare un’espressione lambda e passare le tue condizioni opzionalmente. In TSQL eseguo molte delle operazioni seguenti per rendere opzionali i parametri:

WHERE Field = @FieldVar O @FieldVar È NULL

È ansible duplicare lo stesso stile con un lambda seguente (un esempio di verifica dell’autenticazione):

MyDataContext db = new MyDataContext ();

void RunQuery (stringa param1, stringa param2, int? param3) {

Func checkUser = user =>

((param1.Length> 0)? user.Param1 == param1: 1 == 1) &&

((param2.Length> 0)? user.Param2 == param2: 1 == 1) &&

((param3! = null)? user.Param3 == param3: 1 == 1);

Utente foundUser = db.Users.SingleOrDefault (checkUser);

}

Recentemente ho avuto un simile requisito e alla fine l’ho trovato in MSDN. Esempi CSharp per Visual Studio 2008

Le classi incluse nell’esempio DynamicQuery del download consentono di creare query dinamiche in fase di runtime nel seguente formato:

 var query = db.Customers. Where("City = @0 and Orders.Count >= @1", "London", 10). OrderBy("CompanyName"). Select("new(CompanyName as Name, Phone)"); 

Usando questo puoi build una stringa di query dynamicmente in fase di runtime e passarla nel metodo Where ():

 string dynamicQueryString = "City = \"London\" and Order.Count >= 10"; var q = from c in db.Customers.Where(queryString, null) orderby c.CompanyName select c; 

Ho risolto questo problema con un metodo di estensione per consentire a LINQ di essere abilitato condizionalmente nel mezzo di un’espressione fluida. Ciò elimina la necessità di scomporre l’espressione con istruzioni if .

.If() metodo di estensione:

 public static IQueryable If( this IQueryable source, bool condition, Func, IQueryable> branch) { return condition ? source : branch(source); } 

Questo ti permette di fare questo:

 return context.Logs .If(filterBySeverity, q => q.Where(p => p.Severity == severity)) .If(filterByUser, q => q.Where(p => p.User == user)) .ToList(); 

Basta usare l’operatore && di C #:

 var items = dc.Users.Where(l => l.Date == DateTime.Today && l.Severity == "Critical") 

Modifica: Ah, è necessario leggere più attentamente. Volevi sapere come aggiungere in modo condizionale clausole aggiuntive. In tal caso, non ne ho idea. 🙂 Quello che probabilmente farei è solo preparare diverse query ed eseguire quella giusta, a seconda di cosa ho finito per aver bisogno.

Potresti usare un metodo esterno:

 var results = from rec in GetSomeRecs() where ConditionalCheck(rec) select rec; ... bool ConditionalCheck( typeofRec input ) { ... } 

Funzionerebbe, ma non può essere suddiviso in alberi di espressione, il che significa che Linq a SQL eseguirà il codice di controllo su ogni record.

In alternativa:

 var results = from rec in GetSomeRecs() where (!filterBySeverity || rec.Severity == severity) && (!filterByUser|| rec.User == user) select rec; 

Potrebbe funzionare negli alberi di espressione, il che significa che Linq to SQL sarebbe ottimizzato.

Bene, quello che pensavo fosse che tu potessi inserire le condizioni del filtro in un elenco generico di predicati:

  var list = new List { "me", "you", "meyou", "mow" }; var predicates = new List>(); predicates.Add(i => i.Contains("me")); predicates.Add(i => i.EndsWith("w")); var results = new List(); foreach (var p in predicates) results.AddRange(from i in list where p.Invoke(i) select i); 

Ciò si traduce in una lista contenente “me”, “meyou” e “falciare”.

Potresti ottimizzare questo facendo il foreach con i predicati in una funzione completamente diversa da quella di tutti i predicati.