Risposte:
se vuoi filtrare solo se vengono passati 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 delle espressioni sarà esattamente quello che desideri. In questo modo l'SQL creato sarà esattamente ciò di cui hai bisogno e niente di meno.
LINQ to Entities does not recognize the method 'System.String get_Item(System.String)' method, and this method cannot be translated into a store expression.
Se è necessario filtrare la base su un elenco / array, utilizzare quanto segue:
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();
}
Ho finito con una risposta simile a quella di Daren, ma con un'interfaccia 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();
Questo costruisce la query prima di raggiungere il database. Il comando non verrà eseguito fino alla fine .ToList ().
Quando si tratta di linq condizionale, mi piacciono molto i filtri e il modello dei tubi.
http://blog.wekeroad.com/mvc-storefront/mvcstore-part-3/
Fondamentalmente si crea un metodo di estensione per ogni caso di filtro che accetta IQueryable e un parametro.
public static IQueryable<Type> HasID(this IQueryable<Type> query, long? id)
{
return id.HasValue ? query.Where(o => i.ID.Equals(id.Value)) : query;
}
Ho risolto questo problema con un metodo di estensione per consentire a LINQ di essere abilitato in modo condizionale nel mezzo di un'espressione fluente. Ciò elimina la necessità di suddividere l'espressione con if
dichiarazioni.
.If()
metodo di estensione:
public static IQueryable<TSource> If<TSource>(
this IQueryable<TSource> source,
bool condition,
Func<IQueryable<TSource>, IQueryable<TSource>> branch)
{
return condition ? branch(source) : 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();
Ecco anche una IEnumerable<T>
versione che gestirà la maggior parte delle altre espressioni LINQ:
public static IEnumerable<TSource> If<TSource>(
this IEnumerable<TSource> source,
bool condition,
Func<IEnumerable<TSource>, IEnumerable<TSource>> branch)
{
return condition ? branch(source) : source;
}
Un'altra opzione potrebbe essere quella di utilizzare qualcosa come il PredicateBuilder discusso qui . Ti consente 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, necessario per il funzionamento di questo metodo. Ho una domanda su questo problema qui .
Facendo questo:
bool lastNameSearch = true/false; // depending if they want to search by last name,
avendo questo nella where
dichiarazione:
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ù carina ma puoi usare un'espressione lambda e passare le tue condizioni facoltativamente. In TSQL eseguo molte delle seguenti operazioni per rendere i parametri opzionali:
WHERE Field = @FieldVar OR @FieldVar È NULL
Puoi duplicare lo stesso stile con il seguente lambda (un esempio di verifica dell'autenticazione):
MyDataContext db = new MyDataContext ();
void RunQuery (string param1, string 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 requisito simile e alla fine l'ho trovato in MSDN. Esempi di CSharp per Visual Studio 2008
Le classi incluse nell'esempio DynamicQuery del download consentono di creare query dinamiche in fase di esecuzione 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 costruire una stringa di query dinamicamente in fase di runtime e passarla al 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;
Basta usare l'operatore && di C #:
var items = dc.Users.Where(l => l.Date == DateTime.Today && l.Severity == "Critical")
Modifica: Ah, ho bisogno di leggere con più attenzione. Volevi sapere come aggiungere in modo condizionale clausole aggiuntive. In tal caso, non ne ho idea. :) Quello che probabilmente farei è semplicemente preparare diverse query ed eseguire quella giusta, a seconda di ciò di cui ho bisogno.
Potresti usare un metodo esterno:
var results =
from rec in GetSomeRecs()
where ConditionalCheck(rec)
select rec;
...
bool ConditionalCheck( typeofRec input ) {
...
}
Questo funzionerebbe, ma non può essere suddiviso in alberi di espressione, il che significa che Linq to 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;
Ciò potrebbe funzionare negli alberi delle espressioni, il che significa che Linq to SQL sarebbe ottimizzato.
Bene, quello che pensavo fosse che potresti inserire le condizioni del filtro in un elenco generico di predicati:
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);
Il risultato è un elenco contenente "me", "meyou" e "mow".
Potresti ottimizzarlo eseguendo il foreach con i predicati in una funzione completamente diversa che esegue l'OR di tutti i predicati.