Antworten:
Wenn Sie nur filtern möchten, wenn bestimmte Kriterien erfüllt sind, gehen Sie wie folgt vor
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);
Auf diese Weise kann Ihr Ausdrucksbaum genau das sein, was Sie möchten. Auf diese Weise ist das erstellte SQL genau das, was Sie brauchen, und nicht weniger.
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.
Wenn Sie die Basis nach einer Liste / einem Array filtern müssen, verwenden Sie Folgendes:
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();
}
Ich beendete die Verwendung einer Antwort ähnlich der von Daren, jedoch mit einer IQueryable-Oberfläche:
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();
Dadurch wird die Abfrage aufgebaut, bevor die Datenbank aufgerufen wird. Der Befehl wird erst am Ende von .ToList () ausgeführt.
Wenn es um bedingte Linq geht, mag ich das Filter- und Rohrmuster sehr.
http://blog.wekeroad.com/mvc-storefront/mvcstore-part-3/
Grundsätzlich erstellen Sie eine Erweiterungsmethode für jeden Filterfall, der IQueryable und einen Parameter enthält.
public static IQueryable<Type> HasID(this IQueryable<Type> query, long? id)
{
return id.HasValue ? query.Where(o => i.ID.Equals(id.Value)) : query;
}
Ich habe dies mit einer Erweiterungsmethode gelöst, damit LINQ in der Mitte eines fließenden Ausdrucks bedingt aktiviert werden kann. Dadurch entfällt die Notwendigkeit, den Ausdruck mit if
Anweisungen aufzubrechen .
.If()
Erweiterungsmethode:
public static IQueryable<TSource> If<TSource>(
this IQueryable<TSource> source,
bool condition,
Func<IQueryable<TSource>, IQueryable<TSource>> branch)
{
return condition ? branch(source) : source;
}
Dies ermöglicht Ihnen Folgendes:
return context.Logs
.If(filterBySeverity, q => q.Where(p => p.Severity == severity))
.If(filterByUser, q => q.Where(p => p.User == user))
.ToList();
Hier ist auch eine IEnumerable<T>
Version, die die meisten anderen LINQ-Ausdrücke verarbeitet:
public static IEnumerable<TSource> If<TSource>(
this IEnumerable<TSource> source,
bool condition,
Func<IEnumerable<TSource>, IEnumerable<TSource>> branch)
{
return condition ? branch(source) : source;
}
Eine andere Möglichkeit wäre, etwas wie den hier diskutierten PredicateBuilder zu verwenden . Sie können Code wie folgt schreiben:
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;
Beachten Sie, dass dies nur für Linq 2 SQL geeignet ist. EntityFramework implementiert nicht Expression.Invoke, das erforderlich ist, damit diese Methode funktioniert. Ich habe eine Frage bezüglich dieses Problems hier .
Dies tun:
bool lastNameSearch = true/false; // depending if they want to search by last name,
mit diesem in der where
Aussage:
where (lastNameSearch && name.LastNameSearch == "smith")
bedeutet , dass , wenn die endgültige Abfrage erstellt, wenn lastNameSearch
ist false
die Abfrage vollständig jede SQL für den Nachnamen Suche auslassen wird.
Es ist nicht die schönste Sache, aber Sie können einen Lambda-Ausdruck verwenden und Ihre Bedingungen optional übergeben. In TSQL mache ich viele der folgenden Schritte, um Parameter optional zu machen:
WHERE Field = @FieldVar ODER @FieldVar IST NULL
Sie können denselben Stil mit dem folgenden Lambda duplizieren (ein Beispiel für die Überprüfung der Authentifizierung):
MyDataContext db = new MyDataContext ();
void RunQuery (Zeichenfolge param1, Zeichenfolge 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);
Benutzer foundUser = db.Users.SingleOrDefault (checkUser);
}}
Ich hatte kürzlich eine ähnliche Anforderung und fand diese schließlich in der MSDN. CSharp-Beispiele für Visual Studio 2008
Mit den im DynamicQuery-Beispiel des Downloads enthaltenen Klassen können Sie zur Laufzeit dynamische Abfragen im folgenden Format erstellen:
var query =
db.Customers.
Where("City = @0 and Orders.Count >= @1", "London", 10).
OrderBy("CompanyName").
Select("new(CompanyName as Name, Phone)");
Auf diese Weise können Sie eine Abfragezeichenfolge zur Laufzeit dynamisch erstellen und an die Where () -Methode übergeben:
string dynamicQueryString = "City = \"London\" and Order.Count >= 10";
var q = from c in db.Customers.Where(queryString, null)
orderby c.CompanyName
select c;
Verwenden Sie einfach den && Operator von C #:
var items = dc.Users.Where(l => l.Date == DateTime.Today && l.Severity == "Critical")
Edit: Ah, muss genauer lesen. Sie wollten wissen, wie Sie zusätzliche Klauseln bedingt hinzufügen können. In diesem Fall habe ich keine Ahnung. :) Was ich wahrscheinlich tun würde, ist einfach mehrere Abfragen vorzubereiten und die richtige auszuführen, je nachdem, was ich letztendlich brauchte.
Sie können eine externe Methode verwenden:
var results =
from rec in GetSomeRecs()
where ConditionalCheck(rec)
select rec;
...
bool ConditionalCheck( typeofRec input ) {
...
}
Dies würde funktionieren, kann aber nicht in Ausdrucksbäume unterteilt werden, was bedeutet, dass Linq to SQL den Prüfcode für jeden Datensatz ausführen würde.
Alternative:
var results =
from rec in GetSomeRecs()
where
(!filterBySeverity || rec.Severity == severity) &&
(!filterByUser|| rec.User == user)
select rec;
Dies könnte in Ausdrucksbäumen funktionieren, was bedeutet, dass Linq to SQL optimiert wird.
Ich dachte, Sie könnten die Filterbedingungen in eine allgemeine Liste von Prädikaten aufnehmen:
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);
Das Ergebnis ist eine Liste mit "Ich", "Ich" und "Mähen".
Sie können dies optimieren, indem Sie foreach mit den Prädikaten in einer völlig anderen Funktion ausführen, die alle Prädikate ODER-verknüpft.