SQL Abfrage in LINQ Syntax umwandeln

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 36 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    SQL Abfrage in LINQ Syntax umwandeln

    Hallo,

    die LINQ Syntax ist auf den ersten Blick recht unverständlich, ich weiß wie man einen SQL baut, aber übertragen kann ich es nicht. Kann jemand vielleicht mal ein Beispiel übersetzen?

    Quellcode

    1. Select t.* From table1 t, table2 s Where t.col2 = s.col2 Order By t.col1


    Viele Grüße
    so baut man aber keinen Sql.
    google die w3c - Ergebnisse zum Inner Join - Sql-Schlüsselwort.
    Inner Join ist exponential performanter als dein VereinigungsMengen-Konstrukt.
    Dann poste das korrigierte Sql, dann kann man daran die Linq-Syntax aufzeigen.

    Linq ist übrigens deutlich einfachr, weil Intellisense sinnvolle Vorschläge macht. Sql-Coden ist ja noch auf dem Stand 1970 stehengeblieben, wo man höchstens einen Text-Editor verfügbar hatte.
    Oh , du bist auf einem Holzweg, es geht nicht darum SQL zu ersetzen, das kann LINQ nicht. LINQ "wirkt" im Framework, SQL auf der Datenbank, es geht um ORM.
    m.heise.de/developer/artikel/V…ork-227256.html?seite=all

    Ich mache hier keine Werbung für das Entidy Framework um das klar und deutlich zu sagen, es gibt auch andere, sehr bekannte ORM wie Dapper z.B.

    Haudruferzappeltnoch schrieb:

    SQL-Abfrage

    1. Select t.* From table1 as t Inner Join table2 as s On t.col2 = s.col2 Order By t.col1
    wird zu

    VB.NET-Quellcode

    1. Dim results = From t In table1 Join s In table2 On t.col2 Equals s.col2 Order By t.col1 Select t
    Du siehst: Eiglich alles dasselbe, nur das Select-Schlüsselwort ist nach hinten gewandert, was im Grunde auch sinnvoller ist.
    Ich habe mir folgende Vorraussetzungen geschaffen, um den Code entwickeln zu können:

    VB.NET-Quellcode

    1. Dim table1 = {New With {.col1 = "", .col2 = ""}}
    2. Dim table2 = table1
    Somit hatte ich zwei Tabellen-Objekte, mit je den Properties col1, col2 (dass es keine DataTables sind spielt für Linq keine Rolle - table1, table2 sind Enumerables (also Listen) typisierter Objekte, dassisderPunkt).
    Kopier dir das mal irgendwo rein, sodass es kompiliert, und tipp in einer Zeile darunter dann meine Lösung händisch ab:

    VB.NET-Quellcode

    1. Dim results = From t In table1 Join s In table2 On t.col2 Equals s.col2 Order By t.col1 Select t
    Du wirst sehen, Intellisense macht währenddessen zielführende Vorschläge zur Syntax.



    Haudruferzappeltnoch schrieb:

    Nein ich meine wären die gleichen Abfragen in LINQ schneller als in z.B. MSSQL? Wahrscheinlich nicht.
    Doch.
    Vor allem du musst keine Connection öffnen, Command, DataAdapter, blablabla bauen, zur DB schicken, die rechnets (blitzgeschwind!! - zugegebenermassen) aus, und packt das schön ein, und schickts zurück, und der DataAdapter konvertiert das wieder in .Net-Typen, blablabla....

    Und wie gesagt: die erste Query ist Linq sogar schneller als MSSQL.
    Allerdings hat MSSQL einen Monster-Cache, und erstaunliche Optimierungen.
    Wenn also viele gleichartige solche Abfragen einlaufen, dann rennt MSSQL dem Linq davon, weil der rechnets jedesmal auch wirklich neu aus.
    Aber wg Overhead wird sich diese MSSQL-Stärke erst bei wasweissichwieviel Millionen Datensätzen auswirken.
    Und wie gesagt: es muss dieselbe Query mehrmals gestellt werden, damit MSSQL einfach mal in sein Cache langen kann statt rechnen.

    Also der Vergleich hinkt irgendwie

    Weiters ists völlig irrelevant.
    Linq macht sowas in 0,5ms, und selbst wenn MSSQL es unter iwelchen Bedingungen dann in 0,3ms schafft - ja was? 0,2ms Performance-Gewinn - wer hat was davon?

    Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Oh vielen Dank.

    So kann ich das nachvollziehen. Mich hat das From ... In ... komplett verwirrt. Das ist nur die Benennung... Wieso nimmt man da nicht As? Da steckt doch bestimmt noch mehr dahinter.

    Ok wenn das Connection öffnen der aufwendige Teil ist, darf ich fragen woher du deine Daten so nimmst?
    Weil wenn ich ohne Query irgendwas ziehen würde bräuchte ich ja auch eine Connection und so weiter.

    Meine Spalte kann ich außerhalb des LINQ nicht mit ihrem Namen ansprechen. ​DataSet1.TestTable.Prüfnummer gibt mir "Prüfnummer ist kein Member..." Oder liegts am Dim?

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Haudruferzappeltnoch“ ()

    Ah die Geschichte hab ich auch noch nicht drin.
    Wenn ich das auf mein dgv ziehe bleibt das wahrscheinlich eine Klasse also Datentyp.
    Wenn ich die Instanz dann erzeuge und ändere dann hat das wahrscheinlich keinen Einfluss auf das DGV.

    So werden mir die Spaltennamen mit "Column" dahinter angeboten:

    VB.NET-Quellcode

    1. Dim ds as DataSet1 = New DataSet1()
    2. ds.Table1.PrüfnummerColumn


    So instanziere ich das DataSet, muss ich die Table1 auch noch instanzieren? Dim dt as DataSet1.Table1 = New DataSet1.Table1()
    Da krieg ich Fehlermeldungen


    So keine Fehlermeldungen aber Prüfnummer auch noch mit Column, vielleicht gehört das so?

    VB.NET-Quellcode

    1. Dim ds As DataSet1 = New DataSet1()
    2. Dim dt1 As DataSet1.Table1DataTable = New DataSet1.Table1DataTable()
    3. Dim dt2 As DataSet1.Table2DataTable = New DataSet1.Table2DataTable()


    Der LINQ sieht dann so aus:

    VB.NET-Quellcode

    1. Dim results = From t in dt1 Join s in dt2 On t.Prüfnummer Equals s.Prüfnummer Select t


    Wenn ich im DGV die DataSource auf die results ändere sehe ich aber nichts.

    Dieser Beitrag wurde bereits 8 mal editiert, zuletzt von „Haudruferzappeltnoch“ ()

    Nein, ein typDataset ist voll ausgestattet.
    Alle Tabellen darin sind schon da, an der richtigen Stelle, richtig miteinander verknüpft, und gut.
    NIchts weiter instanzieren!
    Es ist alles drin was du brauchst und wie du es brauchst. Noch mehr zu erstellen kann nur Chaos erzeugen.

    VB.NET-Quellcode

    1. Dim ds As DataSet1 = New DataSet1()
    2. Dim dt1 As DataSet1.Table1DataTable = ds.Table1
    3. Dim dt2 As DataSet1.Table2DataTable = ds.Table2

    oder besser:

    VB.NET-Quellcode

    1. Dim ds = New DataSet1()
    2. Dim dt1 = ds.Table1
    3. Dim dt2 = ds.Table2
    Mehr muss der Frosch nicht kosten (und darf er auch nicht).
    Visualstudio meint es gut mit dir, und will dir Schreibarbeit ersparen.

    Haudruferzappeltnoch schrieb:

    Wenn ich im DGV die DataSource auf die results ändere sehe ich aber nichts.
    Eine Datasource ist auch nix zum hin-und-her-ändern wie bolle.
    Das Databinding richtet man im Form-Designer ein, und dann lässt man zur Laufzeit die Finger davon.

    Du kannst, wenn du willst, ein weiteres Dgv aufs Form tun, ungebunden.
    Dem kannste glaub deine Query als Datasource hinwerfen, und das zeigt dann vielleicht was an.
    (Ganz sicher bin ich nicht, weil ich arbeite nicht so.)

    Hmm - aber eiglich müsste das sogar gehen. Also wenn du diese Query einem DGV andrehst, das an eine Table1 gebunden ist, dann geht das.
    Weil deine Query wirft ja Table1Rows aus - die würden in dem Falle passen.
    Wenn das Dgv hingegen an eine Table2 gebunden ist, passtes eher nicht (oder allenfalls teilweise). Weil Table1Row ist nicht Table2Row.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Ohje, da trau ich mich kaum zu fragen, wie stellst du denn eine Query dar? Oder musst du die nicht sehen können?

    ErfinderDesRades schrieb:


    Hmm - aber eiglich müsste das sogar gehen. Also wenn du diese Query einem DGV andrehst, das an eine Table1 gebunden ist, dann geht das.

    Das DGV war vorher an die BindingSource für Table1 gebunden. Das wird dann wohl das Problem sein

    Haudruferzappeltnoch schrieb:

    Ohje, da trau ich mich kaum zu fragen, wie stellst du denn eine Query dar? Oder musst du die nicht sehen können?
    Ich würde zusehen, ob man die Datensätze iwie markieren kann.
    In einem anderen Thread schreibst du da ja in die PrüfnummerK-Spalte dann ja eine Zahl.
    Sowas kann man nutzen, um der bsTable1 einen Filter zu setzen: bsTable1.Filter = "PrüfnummerK > 0"

    Die Query selbst zu einer Datasource machen - probierma:

    VB.NET-Quellcode

    1. Dim results = From t in dt1 Join s in dt2 On t.Prüfnummer Equals s.Prüfnummer Select t
    2. dgvTable1.DataSource = results.AsDataView
    Aber wahrscheinlich gehts nicht, weil bei gejointen Queries die .AsDataView-Extension abspackt.
    Ah, du meinst ich markiere mit der Query und filter dann die normale Anzeige.

    Was ist denn results genau? Eine Liste von DataRows? Oder eine DataTable? Oder noch was anderes?
    Ich müsste ja dementsprechend die Zeilennummer auslesen aus der Query um in der Table1 die betreffende Zeile zu finden und zu markieren.
    Habs rausgefunden, allerdings bleibe ich ratlos wie ich da Information rauskriege, ich wollte es konvertieren, damit ich es ansprechen kann, aber das funktioniert leider nicht.

    VB.NET-Quellcode

    1. Dim View = From b In DataSet1.Table1 Join s In DataSet1.Table2 On b.Prüfnummer Equals s.Prüfnummer Select b
    2. Dim viewlist As List(Of DataRow)
    3. viewlist = CType(View, List(Of DataRow))

    Das Objekt des Typs "<JoinIterator>d__38`4[myproject.DataSet1+Table1Row,myproject.DataSet1+Table2Row,System.Decimal,myproject.DataSet1+Table1Row]" kann nicht in Typ "System.Collections.Generic.List`1[System.Data.DataRow]" umgewandelt werden
    Wenn .ToList() nicht geht, dann fehlen dir Importe - Ich glaub Imports System.Linq
    .ToList() muss gehen - Ich könnte ohne das überhaupt nicht. Also sowas:

    VB.NET-Quellcode

    1. Dim View = From b In DataSet1.Table1 Join s In DataSet1.Table2 On b.Prüfnummer Equals s.Prüfnummer Select b
    2. Dim viewlist As List(Of DataRow) = View.ToList
    Aber wenn du es nur einmal mit ForEach durlaufen willst, dann brauchst du auch kein .ToList:

    VB.NET-Quellcode

    1. Dim View = From b In DataSet1.Table1 Join s In DataSet1.Table2 On b.Prüfnummer Equals s.Prüfnummer Select b
    2. For Each itm in View
    3. '... schau hier mal nach, welchen Datentyp itm hat!
    4. next
    Weil ein Iterator, wie der <JoinIterator>d__38'kjekls blabla schlagmichtot... ist eben iterierbar.