Laden...

[gelöst] Dynamische Where Klausel in Linq

Erstellt von Byteteufel vor 13 Jahren Letzter Beitrag vor 10 Jahren 5.979 Views
B
Byteteufel Themenstarter:in
35 Beiträge seit 2010
vor 13 Jahren
[gelöst] Dynamische Where Klausel in Linq

Hallo zusammen,

auch wenn ich hier schon diverses gelesen haben, haben mich die Beiträge nicht nach vorn gebracht.

Also, ich lasse in einer "Suchmaske" optional Felder füllen und möchte diese dann als Suchfilter in der Where-Klausel abfragen.
Bei den Feldern "Fängt an mit" ist es kein Problem, nun aber gibt es Felder die "Entspricht" beinhalten.
Wenn ich nun bei den Entspricht-Feldern KEINE Daten übergebe und ich auf Equal abfrage, bekomme ich logischer Weise ein leeres Ergebnis.

In herkömmlichen SQL Schreibweise hätte ich mit

IF Suchattribut > leer dann "and Datenbankfeld = :Suchattribut"

die Abfrage dynamisch gestaltet.

Wenn es so etwas nicht in LINQ gibt, müsste ich für jede Abfragevariante eine extra Methode erstellen. Dann würder bei späterer Wartung aber bei Feldergänzungen etc. jeweils der Aufwand steigen.


          var custs =
             from c in db.BESTELLUNG
             join h in db.HERSTELLER on c.HERSTELLER_ID equals h.HERSTELLER_ID into tempHST
             from hst in tempHST.DefaultIfEmpty()
             join k in db.KUNDE on c.KUNDE_ID equals k.KUNDE_ID into tempKU
             from kun in tempKU.DefaultIfEmpty()
             where
             c.BESTELLNUMMER.StartsWith(myBestellungSuche.Bestellnummer) &&
             hst.NAME_1.StartsWith(myBestellungSuche.Hersteller) &&
             kun.KUNDENNUMMER.StartsWith(myBestellungSuche.Kundennummer) &&
             c.LIEFER_NAME_1.StartsWith(myBestellungSuche.Liefer_Name_1) &&
             c.LIEFER_NAME_2.StartsWith(myBestellungSuche.Liefer_Name_2) 
// Hier ist das Problem....
          //   c.BESTELLDATUM.Equals(myBestellungSuche.Bestelldatum) &&
         //    c.BESTELLSTATUS.Equals(myBestellungSuche.Bestellstatus) &&
           //  c.BESTELLART.Equals(myBestellungSuche.Bestellart)

             select new { .... };

           return custs;

Wie müsste ich das Problem lösen?

Danke für die Hilfe.

Gruß

Axel

1.552 Beiträge seit 2010
vor 13 Jahren

Hallo Byteteufel

In herkömmlichen SQL Schreibweise hätte ich mit IF Suchattribut > leer dann "and Datenbankfeld = :Suchattribut"

das kannst du wohl trotzdem.

&& (string.NullOrEmpty(myBestellungSuche.Bestelldatum1) && BedingungWennSuchattributLeer) || c.BESTELLDATUM.Equals(myBestellungSuche.Bestelldatum)

Note: Es kann sein dass Linq nicht die Methode string.IsNullOrEmpty(string s) anerkennt. Dann musst du es mit s == null || s.Lenght = 0 austauschen

Gruß
Michael

Mein Blog
Meine WPF-Druckbibliothek: auf Wordpress, myCSharp

203 Beiträge seit 2006
vor 13 Jahren

wenn du wirklich alles in eine anweisung packen willst, würde ich es folgendermaßen darstellen


var custs =
	from c in db.BESTELLUNG
	join h in db.HERSTELLER on c.HERSTELLER_ID equals h.HERSTELLER_ID into tempHST
	from hst in tempHST.DefaultIfEmpty()
	join k in db.KUNDE on c.KUNDE_ID equals k.KUNDE_ID into tempKU
	from kun in tempKU.DefaultIfEmpty()
	where
		c.BESTELLNUMMER.StartsWith(myBestellungSuche.Bestellnummer) &&
		hst.NAME_1.StartsWith(myBestellungSuche.Hersteller) &&
		kun.KUNDENNUMMER.StartsWith(myBestellungSuche.Kundennummer) &&
		c.LIEFER_NAME_1.StartsWith(myBestellungSuche.Liefer_Name_1) &&
		c.LIEFER_NAME_2.StartsWith(myBestellungSuche.Liefer_Name_2) &&
		(!string.IsNullOrEmpty(myBestellungSuche.Bestelldatum) ? c.BESTELLDATUM.Equals(myBestellungSuche.Bestelldatum) : true) &&
		(!string.IsNullOrEmpty(myBestellungSuche.Bestellstatus) ? c.BESTELLSTATUS.Equals(myBestellungSuche.Bestellstatus) : true) &&
		(!string.IsNullOrEmpty(myBestellungSuche.Bestellart) ? c.BESTELLART.Equals(myBestellungSuche.Bestellart) : true) &&
	select new { .... };

B
Byteteufel Themenstarter:in
35 Beiträge seit 2010
vor 13 Jahren

Hallo zusammen,

danke für die schnelle Hilfe. Ich muss da noch VIEL lernen... macht aber Spaß. 😁

Gruß

Axel

2.891 Beiträge seit 2004
vor 13 Jahren

In herkömmlichen SQL Schreibweise hätte ich mit IF Suchattribut > leer dann "and Datenbankfeld = :Suchattribut" die Abfrage dynamisch gestaltet. Wenn es so etwas nicht in LINQ gibt,[...]

Geht ebenso mit LINQ:


var query = from c in db.BESTELLUNG ...;

if (!String.IsNullOrEmpty(myBestellungSuche.Bestelldatum))
   query = query.Where(c => 
c.BESTELLDATUM==myBestellungSuche.Bestelldatum);
if (!String.IsNullOrEmpty(myBestellungSuche.Bestellstatus)) 
   query = query.Where(c => c.BESTELLSTATUS==myBestellungSuche.Bestellstatus);
if (!String.IsNullOrEmpty(myBestellungSuche.Bestellart))
   query = query.Where(c => c.BESTELLART==myBestellungSuche.Bestellart);

Gruß,
dN!3L

P.S.: Noch zwei generelle Fragen:
Was hast du für einen LINQ-Provider? LINQ2SQL? Wenn du die Assoziationen zwischen Bestellung<>Hersteller und Bestellung<>Kunde ordentlich im Model definiert hast, brauchst du kein Join. Ich habe in noch keiner einzigen LINQ-Abfrage jemals ein Join gebraucht. Du denkst noch zu viel SQL. 😃
Warum nimmst du nicht "==" statt "Equals()"?

B
Byteteufel Themenstarter:in
35 Beiträge seit 2010
vor 13 Jahren

Hallo,

in der Tat denke ich tatsächlich noch zuviel SQL... ist auch für mich, genau wie WPF ein echter Kulturschock. 8o Aber es lohnt sich bestimmt. 👍

Aktuell habe ich mit dem Designer noch nicht experimentiert.

Ferner habe ich bei Datumsfeldern noch Probleme:


                         (!string.IsNullOrEmpty(myBestellungSuche.Bestelldatum.ToString()) ? c.BESTELLSTATUS.Equals(myBestellungSuche.Bestelldatum) : true) 

Das Attribute "myBestellungSuche.Bestelldatum" ist vom Typ DateTime und in der Datenbank ist der Typ: "BESTELLUNG.Bestelldatum" auch vom Typ DateTime.

Ein Datumsfeld hat als Startwert ein Datum "01.01.0001", welches aber die Datenbank beim Insert abweist.

Wie geht Ihr hier mit Datumsfeldern um?

Gruß

Axel

1.373 Beiträge seit 2004
vor 13 Jahren

Wenn das Datumsfeld optional ist, mach doch ein Nullable davon, also DateTime?. Dann geht datum.HasValue etc.

B
Byteteufel Themenstarter:in
35 Beiträge seit 2010
vor 13 Jahren

Ich liebe dieses Forum... 😁 😁 😁

Das war die Lösung.

Danke.

Gruß

Axel

S
8 Beiträge seit 2013
vor 10 Jahren

Hallo zusammen,
hoffe ihr könnt mir helfen.

Habe mich nach eurer Anleitung gehalten doch leider funktioniert es bei mir nicht.


protected void Button1_Click(object sender, EventArgs e)
    {

        using (DataDataContext db = new DataDataContext())
        {
            var data2 = (from b in db.Datensatz
                        if (!String.IsNullOrEmpty(DropDownList8.SelectedValue))
                            data2 = data2.Where(b=>b.Status == DropDownList8.SelectedValue);

                        select b).ToArray();
        }
        
    }

Nach dem „Where(b=>“ kennt er das Datenfeld nicht.

3.511 Beiträge seit 2005
vor 10 Jahren

Moin,

schau dir bitte die Syntax von Linq noch mal genauer an. So wie es da steht, wird es nie compilieren.

[Hinweis] Syntaxfehler selbst lösen (Compilerfehlermeldungen)
[Hinweis] Wie poste ich richtig? Punkt 1.1 und 1.1.1

Wie die Linq Syntax mit allen Facetten funktioniert kannst du unter 100 Linq Samples nachschauen.

Gruß
Khalid

"Jedes Ding hat drei Seiten, eine positive, eine negative und eine komische." (Karl Valentin)

16.842 Beiträge seit 2008
vor 10 Jahren

Das kann nicht funktionieren, da Du das b bereits nach from deklarierst. Du kannst eine Variable (b im Where) nicht im gleichen Scope verwenden.
Und so ein if in einem Linq funktioniert schon zwei mal nicht.

Das sind C# Grundlagen.

2.891 Beiträge seit 2004
vor 10 Jahren

Habe mich nach eurer Anleitung gehalten[...]

Nein, hast du nicht. Denn dann würde es bei dir so aussehen:


var data2 = (from b in db.Datensatz select b).ToArray();
if (!String.IsNullOrEmpty(DropDownList8.SelectedValue))
   data2 = data2.Where(b=>b.Status == DropDownList8.SelectedValue).ToArray();

Apropos "funktioniert nicht": [Hinweis] Wie poste ich richtig? Punkt 5 (Problem genau beschreiben).

Und so ein if in einem Linq funktioniert schon zwei mal nicht.

Alle Allaussagen sind falsch...

S
8 Beiträge seit 2013
vor 10 Jahren

Jetzt macht es auch Sinn danke dN!3L.
Und natürlich allen anderen 🙂

Natürlich muss ich es erstmal alle Daten Laden und dann erst Sortieren, ich bin von der Sich einer SQL abfrage an die Thematik rangegangen.

Leider haben sich meine Fragen zu LINQ noch nicht ganz beantwortet.

Nachdem ich meine Daten mit deinem Lösung Ansatz "gefiltert" habe.

Wollte ich gerne aus den Datensätzen nach Fehler_Nr Gruppieren und das Ergebnis zusammenzählen
(Das heißt alle Datensätze mit der Fehler_Nr X werden Addiert)

Anschließend bräuchte ich die zu den Addierten Fehler_Nr eine Zeile bei der ich die Fehler_Nr und die Fehleransprache zusammenschreibe.

s.Anhang !

Ergebnis:

Beschreibung Summe

1 Fehleransprache 3
2 Defekt 7
3 Fehler 19

Ziel ist mit den Daten ein Chart zu definieren.

Meine bisherige Lösungsansatz


            var data3 = from x in data2.AsEnumerable()
                        group x by x.Fehler_Ursache into y
                        select new
                        {
                            key = y.Key,                        
                            Summe = y.Sum(z => z.Fehler_Ursache.Fehler_Nr),


                        };



Leider habe ich keinen weiteren Ideen, nachdem ich jetzt 7 Stunden alle möglichen Quellcodes durchgeguckt/getestet habe.
Evtl. fehlt mir nur der richtige Denkanstoß.

Ich sage schon mal Danke für eure Antworten.


Edit:

Habe es zum Teil hinbekommen.

Habe mich dabei an diese PDF gehalten.
Auf der Seite 26 und in meinem Code in der Zeile "HIER" kann man laut dem Buch nach "Summe" und dem Punkt Operanten den Namen für die Balken definieren.

Bei mir ist dies nicht möglich wisst ihr was ich falsch mache


            var query = from x in data1
                        group x by x.Fehler_Ursachen.Fehleransprache into y
                        select new
                        {
                            key = y.Key,
                            Summe = y.Count(),
                        };
                   

            foreach ( var q in query)
            {
                var test = q.Summe;  //<HIER
            Chart1.Series[0].Points.AddXY(test, Convert.ToDouble(q.Summe));
            }