Multiple WHERE-Klausel in Linq

75

Ich bin neu in LINQ und möchte wissen, wie mehrere where-Klauseln ausgeführt werden. Folgendes möchte ich erreichen: Datensätze zurückgeben, indem bestimmte Benutzernamen herausgefiltert werden. Ich habe den folgenden Code ausprobiert, aber nicht wie erwartet funktioniert.

DataTable tempData = (DataTable)grdUsageRecords.DataSource;
var query = from r in tempData.AsEnumerable()
            where ((r.Field<string>("UserName") != "XXXX") || (r.Field<string>("UserName") != "XXXX"))                            
            select r;    

            DataTable newDT = query.CopyToDataTable();

Danke für die Hilfe im Voraus !!!

Ganesha
quelle

Antworten:

115

Nun, Sie können einfach mehrere "where" -Klauseln direkt einfügen, aber ich glaube nicht, dass Sie das wollen. Mehrere „where“ Klauseln mit einem endet mehr restriktiven Filter - ich glaube , Sie wollen weniger restriktiv. Ich denke du willst wirklich:

DataTable tempData = (DataTable)grdUsageRecords.DataSource;
var query = from r in tempData.AsEnumerable()
            where r.Field<string>("UserName") != "XXXX" &&
                  r.Field<string>("UserName") != "YYYY"
            select r;

DataTable newDT = query.CopyToDataTable();

Beachten Sie das && anstelle von ||. Sie möchten die Zeile auswählen, wenn der Benutzername nicht XXXX und der Benutzername nicht JJJJ ist.

EDIT: Wenn Sie eine ganze Sammlung haben, ist es noch einfacher. Angenommen, die Sammlung heißt ignoredUserNames:

DataTable tempData = (DataTable)grdUsageRecords.DataSource;
var query = from r in tempData.AsEnumerable()
            where !ignoredUserNames.Contains(r.Field<string>("UserName"))
            select r;

DataTable newDT = query.CopyToDataTable();

Idealerweise möchten Sie dies so einstellen HashSet<string>, dass der ContainsAnruf nicht lange dauert. Wenn die Sammlung jedoch klein genug ist, ergeben sich keine großen Chancen.

Jon Skeet
quelle
Ich habe eine UserName-Sammlung. Wie übergebe ich es dynamisch an die where-Klausel?
Ganesha
1
Ich weiß, dass dies vor langer Zeit beantwortet wurde, aber mein schneller Vorschlag wäre, zu versuchen, join zu verwenden, anstatt zu enthalten. Ist viel effizienter (insbesondere wenn Ihr enthaltener Datensatz eine angemessene Größe hat).
ArtificialGold
46

@Das Ö

Der LINQ-Übersetzer ist intelligent genug, um Folgendes auszuführen:

.Where(r => r.UserName !="XXXX" && r.UsernName !="YYYY")

Ich habe dies in LinqPad getestet ==> JA, der Linq-Übersetzer ist klug genug :))

Alex
quelle
Intelligent genug bedeutet, dass Linq über zusätzliche Filter verfügt, was die Leistung beeinträchtigt.
Andres Toro
20

@ Jon: Jon, sagst du mit mehreren where-Klauseln, z

var query = from r in tempData.AsEnumerable()
            where r.Field<string>("UserName") != "XXXX" 
            where r.Field<string>("UserName") != "YYYY"
            select r;

ist restriktiver als zu verwenden

var query = from r in tempData.AsEnumerable()
            where r.Field<string>("UserName") != "XXXX" && r.Field<string>("UserName") != "YYYY"
            select r;

Ich denke, sie sind in Bezug auf das Ergebnis gleichwertig.

Ich habe jedoch nicht getestet, ob die Verwendung mehrerer, wo im ersten Beispiel Ursache in 2 Unterabfragen, dh .Where(r=>r.UserName!="XXXX").Where(r=>r.UserName!="YYYY)oder der LINQ-Übersetzer klug genug ist, um ausgeführt zu werden.Where(r=>r.UserName!="XXXX" && r.UsernName!="YYYY")

Theodore Zographos
quelle
6

Sie können auch Bool-Methoden verwenden.

Abfrage:

DataTable tempData = (DataTable)grdUsageRecords.DataSource;
var query = from r in tempData.AsEnumerable()
            where isValid(Field<string>("UserName"))// && otherMethod() && otherMethod2()                           
            select r;   

        DataTable newDT = query.CopyToDataTable();

Methode:

bool isValid(string userName)
{
    if(userName == "XXXX" || userName == "YYYY")
        return false;
    else return true;
}
Tolga Okur
quelle