SQL-String einem DataDridView als DataSource zuweisen

  • VB.NET

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

    SQL-String einem DataDridView als DataSource zuweisen

    Hallo zusammen,

    ich möchte einen SQL-String (ohne MySQL-Server oder ähnliches) einem DataGridView zuweisen.

    Das ich über eine DataTable gehen muss ist mir auch schon klar.

    Mein Projekt arbeitet mit einem Typisierten DataSet (Siehe Thread: Syntaxfehler in From Klausel)

    Diese Daten sollen dann als Basis für ein TreeView dienen. Da die Datenbasis somit aus mehreren Tabellen sich zusammensetzt, geht es meines Wissens nach nur über eine entsprechende SQL-Abfragestring.

    Kann mir mal jemand kurz auf die Sprünge helfen?

    Alles was ich bisher gefunden habe, benötigt einen SQL-Server, denn ich aber nicht verwenden wollte.

    Vielen Dank

    Volker

    *Topic verschoben*

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Marcus Gräfe“ ()

    Ein SQL-String ist erstmal nur genau das: ein String, also ein Text. Das dem DGV als Datasource zuzuweisen, ergibt erstmal so keinen Sinn. Und abhängig davon, wo die Daten sind, musst Du über einen Provider gehen. Wie sollte man sonst auf die Daten zugreifen können? Jeder Anbieter hat da seinen eigenen SQL-"Akzent". Wo sind denn die Daten, die einen SQL-String verlangen, wenn nicht in einer Datenbank?
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Damit hat das Ganze aber nix mehr mit SQL am Hut. Was hast Du damit vor? Wenn es um »Datenabfrage aus der XML« geht: Die Daten werden aus der XML ins tDS (typ. Dataset) geladen (so wie Du geschrieben hast) und von dort aus z.B. mit LINQ rausgeholt. Also aus dem tDS. Nicht aus der XML. Und SQL braucht man da gar nicht.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Hallo VaporiZed,

    vielen Dank erst einmal für den Anstoß in die richtige Richtung.

    Habe mir gerade mal ein Linq Videos angesehen um überhaupt mal etwas zu verstehen.

    Da es hier leider fast nur englische Videos gibt und die Deutschen leider fast alle in C# sind, habe ich mal einfach nach ein wenig Code gegoogled und auf Grund dieser Links stackoverflow.com/questions/11…bles-and-show-all-columns (zwei Tabellen miteinander zu verbinden) folgenden Test für mich erstellt.


    VB.NET-Quellcode

    1. Imports System
    2. Imports System.Linq
    3. Imports System.Xml.Linq
    4. Private Sub
    5. ' per LinQ die TreeView-Daten anzeigen lassen
    6. Dim query = From DT1 In _Modelldatenbank_VB_Net_2019_DatenDataSet.Artikel
    7. Join DT2 In _Modelldatenbank_VB_Net_2019_DatenDataSet.Artikel_Belege
    8. On DT1.Field(Of Int32)("ID") Equals DT2.Field(Of Int32)("ArtikelID")
    9. Where DT1.ArtikelNr = "7182"
    10. Select DT1.ID, DT1.ArtikelBezeichnung, DT2.EndPreis
    11. DGridView_TreeView.DataSource = query.ToList
    12. End Sub


    Was ich bisher verstanden habe (hoffe ich zumindestens), dass
    - Dim Query die Abfrage aufnimmt
    - From DT1 In <Name meins DataSets>.<Name der Tabelle> = DT1 eine Variable in der Abfrage ist für die erste Tabelle
    - Join eine Art "UND" ist und somit weitere Tabellen sich hierüber in die Abfrage einfügen lassen
    - On und Equals verbinden dann die einzelnen Beziehungsfelder der jeweiligen DT-Variablenfelder miteinander, stellen somit die Beziehungen zwischen den Feldern der jeweiligen Tabellen da.
    - Where Zeile legt die Bedingungen bzw. den Filter fest
    - Select sind dann die Tabellen (DT) und Felder, die in dem Ergebnis angezeigt werden sollen.

    Wenn dass bis hier her richtig war, dann ist das recht logisch.

    Wenn ich diese Zeilen aber dann erst einmal zum Testen per Button_Click aufrufe und somit mein DataGridView füllen möchte, dann bekomme ich die Fehlermeldung (siehe Anhang Bild1)

    System.Data.StrongTypingException: "Der Wert für Spalte ArtikelNr in Tabelle Artikel ist DBNull."
    Innere Ausnahme: Ungültige Konvertierung von Typ DBNull in Typ String.

    Ja, es gibt Artikel die haben keine ArtikelNr. Ja das ist auch nicht ganz richtig, aber die Tabelle sollte hier eigentlich Null-Werte erlauben. (siehe Bild2, ist zwar Access, aber auf dieser Basis habe ich mir meine XML-Datei und das DataSet aufgebaut und auch daran nichts verändert).

    Jetzt meine Fragen:

    1. Ist das o. g. soweit richtig verstanden bzw. richtig vom Code her?
    2. Wie kann ich den Fehler beseitigen (ohne jetzt die Daten zu ändern)?
    3. Wofür sind die "Field(of" Anweisungen in der "On-Zeile" da? Gehen würde auch diese Zeile " On DT1.ID Equals DT2.ArtikelID". Kann ich hier noch nicht festgelegte Feldtypen bestimmen wie aus dem Bsp., diese sind ja noch nicht festgelegt worden. Da mein DataSet ja schon kpl. Typisiert ist, müsste es ja eigentlich mit der gerade genannten "kurzen" Schreibweise für meinen Fall richtig sein. Aber der Fehler ist dadurch leider nicht weg.

    Gruß

    Volker
    Bilder
    • Bild1.jpg

      63,11 kB, 1.499×363, 81 mal angesehen
    • Bild2.jpg

      83,97 kB, 377×451, 88 mal angesehen
    1. Dein LINQ-Verständnis kann ich soweit bestätigen.
    2. Das ist Einstellungssache, und zwar im tDS-Designer. Da kannst Du für jede Spalte einer Tabelle festlegen, ob Du Null-Werte erlaubst oder nicht. Wenn das in Deinem Datenmodell Sinn ergibt oder wenn Du nur kurzfristig diese Option brauchst, um Altdaten zu konvertieren, aktivier die Option. Meistens ist es aber so, dass es für Tabelleneinträge keinen Sinn ergibt, dass eine bestimmte Eigenschaft Null ist.
    3. Du kannst (bestimmt) auch schreiben: On DT1.ID = DT2.ArtikelID. Es geht ja um nen simplen Integerwert.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Hallo VaporiZed,

    Danke schön wir die super schnelle Antwort.

    Das mit dem Fehler habe ich auch gerade herausbekommen.

    Habe einfach

    VB.NET-Quellcode

    1. Dim query = From DT1 In _Modelldatenbank_VB_Net_2019_DatenDataSet.Artikel
    2. Join DT2 In _Modelldatenbank_VB_Net_2019_DatenDataSet.Artikel_Belege
    3. On DT1.ID Equals DT2.ArtikelID
    4. Where DT1.Field(Of String)("ArtikelNr") = TBox_ArtikelNr.Text
    5. Select DT1.ID, DT1.ArtikelBezeichnung, DT2.EndPreis
    6. DGridView_TreeView.DataSource = query.ToList


    geschrieben und schon hat es geklappt.

    Bedeutet also, dass man jeden nicht durch den DataSet festgelegten DatenTyp hier festlegen muss, um keine Fehler zu bekommen.

    Na dann kann ich mich an die Umsetzung meiner Abfrage mal ran machen.

    Schönen Sonntag noch.

    Volker
    Ich empfehle immer, bei String keinesfalls Null zuzulassen.
    Stattdessen kann man als DefaultWert "" eintragen - das ist üblicherweise eine ebensogute Darstellung für "nichts eingegeben".
    Und ist in der Auswertung deutlich einfacher.
    DT1.Field(Of String)("ArtikelNr") ist ja schon keine typisierte Programmierung mehr, sondern wieder ein String-Smell + TypUmwandlung.
    DT1.ArtikelNr wäre schon die richtige Property.
    Ein anderer Punkt ist, dass ein Artikel ohne ArtikelNr nach meim Verständnis von 'ArtikelNr' tatsächlich so ungefähr niemals Eingang in einen Artikel-Datenbestand finden dürfte - oder wie kann das mit rechten Dingen zugehen?
    Hallo ErfinderDesRades,

    Vielen Dank für die Infos.

    Das mit der Artikelnr. liegt in meinem Falle daran, dass es manchmal nicht so einfach ist, eine Artikelnr. herauszubekommen und da habe ich halt immer dann keine eingegeben. Klar könnte man in so einem Falle eine DUMMY-Artikelnr. eingeben. Das werde ich wahrscheinlich in diesem Falle auch so machen.

    Aber bei den anderen Feldern bzw. Tabellen ist die "" - Lösung eine wirkliche Alternative. Gilt dies dann auch für Zahlenfelder (0 = Default) und die anderen Typen dann wohl auch.

    Jetzt ist halt die Frage was geht schneller und einfacher, den DataSet noch einmal löschen, die DB dahingehend ändern, dass alle Datensätze/-felder "" oder 0 haben (würde dies dann aber über eine VBA-Schleifenlösung lösen wollen, denn über 100.000 Datensätze insgesamt ändern macht per Hand keinen Spaß) und dann das DataSet neu erstellen.

    Oder gibt es hier eine einfachere Variante?

    Gruß

    Volker
    Nimm den tDS-Inhalt her, mach ne For-Schleife über alle Tabellenzeilen und pack dort, wo derzeit DbNull ist, ein String.Empty rein.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    ich rate ja immer davon ab, mit Datenbank und typDataset herumzuhühnern.
    Meine Empfehlung (wiederholt, gähn!): lass die Datenbank weg.
    DefaultValue und AllowNull=False kannste im Dataset-Designer einstellen.
    Unter Umständen musste nichtmal an den Daten was ändern.
    DefaulValue heisst ja: Wenn nix gesetzt ist (also DbNull) - dann nimm den DefaultValue.

    Aber vorher Komplett-Backup machen!
    Aus so einer Änderung ergeben sich üblicherweise ein paar leicht lösbare FolgeFehler.
    Aber manchmal passiert doch was blödes und alles ist zerschossen. Oder es verhaspelt sich sogar der Dataset-Designer selbst.
    Hallo VaporiZed, Hallo ErfinderDesRades,

    Habe mal folgendes versucht

    VB.NET-Quellcode

    1. Sub DataSet_ändern()
    2. For Each dt As DataTable In Hauptmaske._Modelldatenbank_VB_Net_2019_DatenDataSet.Tables
    3. Dim Data As New DataTable(dt.TableName)
    4. For Each DC In dt.Columns
    5. If InStr(DC.datatype.ToString, "String") > 0 Then
    6. 'If isnothing(DC.defaultvalue) = True Then
    7. ' AltDefaultValue = " DBNull"
    8. ' MsgBox("Tabelle: " & dt.TableName & vbCrLf &
    9. ' "Spaltenname: " & DC.columnname & vbCrLf &
    10. ' "Dataityp: " & DC.datatype.ToString & vbCrLf &
    11. ' "Alter DefaultValue: " & AltDefaultValue)
    12. 'End If
    13. ' Neuen Standardwert setzen
    14. DC.defaultvalue = String.Empty
    15. MsgBox("Tabelle: " & dt.TableName & vbCrLf &
    16. "Spaltenname: " & DC.columnname & vbCrLf &
    17. "Dataityp: " & DC.datatype.ToString & vbCrLf &
    18. "Länge neu DefaultValue " & Len(DC.defaultvalue.ToString))
    19. End If
    20. Next
    21. Next
    22. End Sub


    Bekomme zwar alle Tabellen und hier erst einmal alle Felder die String sind ausgeworfen, aber der DefaultValue wird nicht gesetzt.

    Bei dem ausgeklammerten Teil wollte ich eine DBNull-Prüfung mal versuchen, ist aber leider nichts draus geworden.

    Der Rest läuft zwar anstandslos durch, aber am Ende ist das DataSet immer noch so wie es war.

    Muss man das Ganze noch irgendwie sichern oder ist mein Ansatz schon falsch?

    Für einen Hinweis wäre ich dankbar.

    @EDR: Das mit der DB war jetzt halt nur ein Vorschlag, das DataSet neu zu machen, da ich in Access die DBNull bzw. DefaultValue Sache schon per VBA Code hinbekommen habe. Hab es aber trotzdem mal ausprobiert, funktioniert aber leider dann doch nicht.

    Noch eine andere Frage: DC.defaultvalue und DC.datatype.ToString sind Angaben, bei denen ich nach dem Punkt nicht automatisch etwas vorgeschlagen bekomme. Ist das ein Bug in VB.Net oder mache ich hier noch etwas falsch?

    Gruß
    Volker
    Argh, Augenkrebs!
    Bevor Du weitermachst, bitte die empfohlenen VS-Einstellungen verwenden. Dein Code ist sehr stark VB6-durchsetzt.

    Sobald Du versuchst, alle Tables über einen Kamm zu scheren (Zeile#2), ist's aus mit typisiert. Eine Tabelle, in der es um Autos geht, kann nicht sinnvoll mit einer, in der es um Obst geht, in einem Atemzug genannt werden. Dass da IntelliSense nicht weiterhilft, liegt daran, dass DefaultValue und Co. vom Typ Object sind. Weil Du untypisierte Tabellen und Columns am Wickel hast.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Hallo VaporiZed,

    sorry für den Augenkrebs.

    So die Einstellungen "On Strict on" und den Namespace habe ich geändert so wie in dem Link beschrieben.

    Habe auch schon ein paar Dinge jetzt geändert

    VB.NET-Quellcode

    1. Option Strict On
    2. Module Module1
    3. Sub DataSet_ändern()
    4. Dim ds As DataSet
    5. ds = Hauptmaske._Modelldatenbank_VB_Net_2019_DatenDataSet
    6. For Each dt As DataTable In ds.Tables
    7. If dt.TableName = "Artikel" Then
    8. For Each DataColumn As DataColumn In ds.Tables(dt.TableName).Columns
    9. Dim InString As String
    10. InString = DataColumn.DataType.ToString
    11. If InString.IndexOf("String") > 0 Then
    12. ' Neuen Standardwert setzen
    13. DataColumn.DefaultValue = String.Empty
    14. MessageBox.Show("Tabelle: " & dt.TableName & System.Environment.NewLine &
    15. "Spaltenname: " & DataColumn.ColumnName & System.Environment.NewLine &
    16. "Dataityp: " & DataColumn.DataType.ToString & System.Environment.NewLine &
    17. "Länge neu DefaultValue " & DataColumn.DefaultValue.ToString.Length)
    18. End If
    19. Next
    20. End If
    21. Next
    22. End Sub
    23. End Module


    Option Strict On ist nur als Beweis bzw. Sicherheit drin (kommt später wieder raus)
    Die Zeile If dt.TableName = "Artikel" Then dient auch nur zum Test, da fast alle meine Tabellen im DataSet-Designer übereinander liegen und natürlich die erste Tabelle ganz unten liegt.

    Hier am Rande eine Frage: Wie kann ich den Designer dazu bewegen, die letzte Positionen der Tabellen zu behalten? Dann würde ich gerne hier es auch schön machen.

    Habe gestern dann noch alle Fehler beseitig, so dass die Anwendung jetzt wieder läuft.

    Was ich aber noch nicht verstehe ist folgendes.


    Sobald Du versuchst, alle Tables über einen Kamm zu scheren (Zeile#2), ist's aus mit typisiert. Eine Tabelle, in der es um Autos geht, kann nicht sinnvoll mit einer, in der es um Obst geht, in einem Atemzug genannt werden.


    Hier weiss ich zwar, das man Autos nicht mit Obst vergleichen kann, aber mein Ziel ist es doch, das DataSet bzw. alle Tabellen darin zu durchlaufen und dann von der jeweils aktuellen Tabelle alle String-Tabellenfelder deren DefaultValue Eigenschaft auf "" bzw. String.Empty umzustellen. Daher haben doch die Tabelleninhalte erst einmal hier keine Relevanz. Mich interessiert doch nur die Feldeigenschaft.

    Der Code läuft zwar, aber der DefaultValue-Wert wird nicht geändert.

    Könntest Du mir mal einen Tipp geben, wie es gehen könnte?

    Vielen Dank

    Volker

    Volker Bunge schrieb:

    Option Strict On ist nur als Beweis bzw. Sicherheit drin (kommt später wieder raus)
    Warum willst Du die Versicherung, dass Du weniger Murks coden würdest, kündigen?

    Dein Einwand bzgl. meinem über-den-Kamm-scheren ist berechtigt. Es geht ja hier um eine allgemeine Tabellenbearbeitung. Daher reicht auch die untypisierte Form.

    Was sagt denn Deine MessageBox? Wird sie gezeigt? Statt "Länge neu DefaultValue " & DataColumn.DefaultValue.ToString.Length schreib besser:

    VB.NET-Quellcode

    1. "DefaultValue wurde geändert: " & (DataColumn.DefaultValue Is String.Empty).ToString


    Speicherst Du die Änderungen auch in Deiner DB ab?
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Hallo VaporiZed,

    also Option Strict On ist jetzt aus dem Modul raus. War ja auch nur ein optischer Beweis.

    Dein Vorschlag bringt jetzt die richtige Anzeige, aber im DS-Designer steht in den Eigenschaften immer noch <DBNull>. Dann ist halt die Frage, ob sich hier überhaupt etwas ändern muss und wenn Ja wie man das dann anstellt.

    Die Änderungen werden nur in einer XML gespeichert.

    Gruß
    Volker

    Volker Bunge schrieb:

    Option Strict On ist jetzt aus dem Modul raus

    Aber warum? Option Strict sollte immer aktiv sein. Die wenigen Ausnahmen, wo man mit Option Strict Off arbeiten muss, begrenzt sich auf eine handvoll Spezialfälle!

    Den tDS-Designer wirst Du mit Deinem Programm nicht dazu bringen, was anderes anzuzeigen. Du kannst Deine Tabellen mit Deinem Code nur zur Laufzeit zu anderen Defaultwerten überreden. Da hab ich Dich wohl falsch verstanden. Wenn es Dir um die tDS-Einstellungen geht, geht das nur per Hand, ggf. per Visual-Studio-Makro-Recorder (Nuget-Paket) oder durch Eingriff in die tDS-Designer.vb. Ich habe bisher ur die per-Hand-Variante probiert.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Hallo VaporiZed,

    also noch mal zu Option Strict On: Muss man die jetzt einmalig in der Anwendung aktivieren oder bei jedem Modul? Hab die Videos so verstanden, dass man dies einmalig in der Anwendung einstellt. Gut, man kann sich jetzt daraus eine Vorlage basteln, die dann auf diesen generellen Einstellungen beruht und muss es somit nicht jedes Mal einstellen. Oder habe ich da was falsch verstanden? Die generelle Option Strict Einstellung steht auf On.

    Das mit den DefaultValue Eigenschaften geht also nur per Hand oder mit dem Code. Der Code sollte somit am Anfang der Anwendung einmal durchlaufen und alles ist gut. Für kleinere Projekte mache ich das dann auch schnell per Hand gerne, aber bei dieser Menge an Tabellen warte ich lieber ein paar Sekunden länger und übersehe somit auch kein Tabellenfeld.

    Hast Du eine Ahnung warum meine DS-Designer viele Tabellen übereinander legt?

    Gruß

    Volker

    Volker Bunge schrieb:

    Die generelle Option Strict Einstellung steht auf On.
    Ah perfekt, dann kannst Du die Option Strict On-Zeile in den Dateien weglassen. Es ist eben nur wichtig, dass es aktiv ist.
    Tja, der tDS-Designer ist da manchmal n bisken komisch. Eine Möglichkeit (nachdem Du ein Backup gemacht hast!): alles (aber wirklich alles!) im Designer zu markieren, ausschneiden, einfügen. Dann ordnet VS die Tabellen wieder in "schön" an. Ob das dann allerdings Deinen Erwartungen entspricht, kann ich Dir nicht garantieren.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Ich sortiere mir die Tabellen immer ganz liebevoll genau so hin, dass ich möglichst viele Tabellen sehen kann, und die Relationen mit möglichst wenig Überkreuzungen auskommen. Ich mach auch Tabellen schmaler, wenn die Benennungen das zulassen.
    Eine Zeitlang hat mein Dataset-Designer auch gesponnen, und hat immer mal wieder die Tabellen umgeräumt. Also wenn man das Fenster zu machte und wieder auf, waren die Tabellen wieder voll durcheinander.
    Da behulf ich mich zu guterletzt mit einem Screenshot - den kanner mir nicht wieder versauen.
    Bei mir hat der Dataset-Designer sich mit VS2017 aber sehr gebessert, mussich sagn.