SQL Verbindung richtig trennen?

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

Es gibt 12 Antworten in diesem Thema. Der letzte Beitrag () ist von Facebamm.

    SQL Verbindung richtig trennen?

    Hi,
    ich arbeite an meinem ersten Programm mit SQL Verbindung. Wie schließe ich Verbindungen am Besten wenn ich einen Datenbankzugriff in einem Sub benutze? Normalerweise nutze ich xx.Dispose() und xy.Close(). Nun hatte ich ein Sub indem ich ein Exit Sub genutzt hatte. Da ich gelesen habe, dass ein Exit Sub nicht gerade schön ist wurde dies jetzt anders gelöst, geht jedoch trotzdem während einer Abfrage aus dem Sub bzw schließt die aktuelle Form:

    VB.NET-Quellcode

    1. Private Sub SpeichernBtn_Click(sender As Object, e As EventArgs) Handles SpeichernBtn.Click
    2. Dim dbConnection As New SQLite.SQLiteConnection()
    3. Dim dbCommand As SQLiteCommand
    4. Dim dbReader As SQLiteDataReader
    5. dbConnection.ConnectionString = "Data Source=users.sqlite3;"
    6. dbConnection.Open()
    7. dbCommand = dbConnection.CreateCommand
    8. dbCommand.CommandText = "SELECT * FROM kunden WHERE rfid = " & RFIDBox.Text & ";"
    9. dbReader = dbCommand.ExecuteReader()
    10. If dbReader.Read() Then
    11. dbReader.Close()
    12. MsgBox("Kartennummer bereits vorhanden.")
    13. dbCommand.Dispose()
    14. dbConnection.Close()
    15. Else
    16. dbReader.Close()
    17. dbCommand.CommandText = "INSERT INTO kunden (rfid) VALUES (" & RFIDBox.Text & ");"
    18. dbCommand.ExecuteNonQuery()
    19. dbCommand.Dispose()
    20. dbConnection.Close()
    21. Form1.LadeDaten()
    22. Me.Close()
    23. End If
    24. End Sub


    Wie zu sehen habe ich jetzt einfach zweimal Dispose und Close genutzt. Bei meinen anderen Subs die "hoffentlich" alle bis zum Ende durchlaufen sollte ist jeweils nur ein Dispose und Close am Ende. z.B.

    VB.NET-Quellcode

    1. Private Sub ContextMenuStrip1_ItemClicked(sender As Object, e As ToolStripItemClickedEventArgs) Handles ContextMenuStrip1.ItemClicked
    2. Dim dbConnection As New SQLite.SQLiteConnection()
    3. Dim dbCommand As SQLiteCommand
    4. dbConnection.ConnectionString = "Data Source=users.sqlite3;"
    5. dbConnection.Open()
    6. dbCommand = dbConnection.CreateCommand
    7. Select Case e.ClickedItem.ToString()
    8. Case "Speichern"
    9. If KdnIDBox.Text.Length > 0 Then
    10. dbCommand.CommandText = "UPDATE kunden SET usrid = " & KdnIDBox.Text & " WHERE rfid = " & RFIDBox.Text & ";"
    11. dbCommand.ExecuteNonQuery()
    12. LadeDaten()
    13. Else
    14. MsgBox("Bitte geben Sie eine Kundennummer ein.")
    15. End If
    16. Case "Löschen"
    17. dbCommand.CommandText = "DELETE FROM daten WHERE rfid = " & RFIDBox.Text & ";"
    18. dbCommand.ExecuteNonQuery()
    19. dbCommand.CommandText = "DELETE FROM kunden WHERE rfid = " & RFIDBox.Text & ";"
    20. dbCommand.ExecuteNonQuery()
    21. Case "Karte hinzufügen"
    22. Form2.Show()
    23. End Select
    24. dbCommand.Dispose()
    25. dbConnection.Close()
    26. LadeDaten()
    27. End Sub


    Gibt es hier eine "beste" Möglichkeit wie z.B. nach jedem Execute ein Dispose oder ähnliches?

    Vielen Dank im Voraus,
    Departet
    ich empfehle immer typisierte Datasets, und deren Befüllung mittels DataAdapter. Das eröffnet die Möglichkeit von Databinding, die dein bisheriger Ansatz schon von vornherein verhindert.
    Aber dazu müsstest du dir erstmal eine ziemliche Stange an Grundlagen aneignen - fängt schon mit den grundlegendsten Einstellungen an.
    gugge Datenverarbeitungs-Vorraussetzungen
    Connection Schließen und dann disposen kann man machen. Oder aber die Connection und den Rest per "using" instanziieren, dann muss man das nicht selbst machen.

    Als Tipp:
    Trenne Logik und Oberfläche.DB Zugriffe gehören nicht in die GUI. Schreib dir eine separate Klasse für den DB Zugriff, welche das Speichern/Laden übernimmt. Zusätzlich eine Klasse die Zwischen der GUI und der DB-Zugriff-Klasse vermittelt (hier stehen die SQL Statements z.B.). Sonst schreibst du bei jedem Click eines Buttons den ganzen Kram mit dem DB Zugriff neu... Artet sonst irgendwann gerne mal in Spaghetti Code aus.

    Ich hoffe zudem, dass bei Form1.LadeDaten bzw. Form2.Show() die Form1/Form2 die Instanz ist. Falls nicht, schreib mal in die Erste Zeile deines Codes Option Strict On.
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „mrMo“ ()

    Danke erstmal für die Antworten. Mit Option Strict On bekomme ich Fehlermeldungen bei:

    VB.NET-Quellcode

    1. For Each row In vwDgview.Rows
    2. If SuchenBox.Text = row.Cells(0).Value.ToString Then
    3. row.Selected = True
    4. End If
    5. Next

    "Option Strict On" lässt spätes Binden nicht zu.
    Aber ich binde doch nichts? Oder doch?

    @ErfinderDesRades wie erstelle ich denn ein typisiertes Dataset mit SQLITE? Finde leider absolut keinen Provider für SQLite der sich mit einem typisierten Dataset benutzen lässt.

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

    Departet schrieb:

    Finde leider absolut keinen Provider für SQLite der sich mit einem typisierten Dataset benutzen lässt.
    Das schon probiert:
    system.data.sqlite.org/index.html/doc/trunk/www/index.wiki
    Das ist ein ADO.NET kompatibler SQLite Provider. Ergo solltest du damit typisierte Datasets bedienen können.
    ja, das ist eine irreführende Fehlermeldung. Dort wird unter Bindung was anneres verstanden was Bindung beim Databinding bedeutet.
    die fehlermeldung bedeutet: "ich weiss nicht was row fürn Datentyp ist, und ob dieser eine .Selected-Property hat."

    probierma

    VB.NET-Quellcode

    1. For Each row as vwDgvwiewRow In vwDgview.Rows
    2. If SuchenBox.Text = row.Cells(0).Value.ToString Then
    3. row.Selected = True
    4. End If
    5. Next
    Aber ich bin pessimistisch.
    Ich müsste halt wissen, welchen Datentyp vwDgview hat. Vlt ists ja eine typisierte Datatable, dann wäre mein Vorschlag zutreffend. Wenns was anneres is, muss mans anners machen.

    Departet schrieb:

    wie erstelle ich denn ein typisiertes Dataset mit SQLITE?
    Dassis schwierig - da muss man den richtigen Connector richtig installieren und pi und pa und po.

    Aber wenn du meine Empfehlungen aufmerksam liest, stellst du fest, dass die Einbindung einer Datenbank noch viel zu früh ist.
    Oder anders: Eine Db kann man jederzeit hinterlegen, auch - und vorzugsweise - später, wenn man die anderen Sachen beherrscht.

    Solange du noch mit Option Strict kämpfst, mit Datenmodellierung, typisiertem Dataset, Databinding - solange brauchst du dir die zusätzliche FehlerQuelle Datenbank nicht auch noch antun.
    Fehlerquellen multiplizieren sich, also wenn du beim Dataset 100 Sachen falsch machen kannst, und beim Datenbank-Zugriff auch 100, dann ergibt das 10000 mögliche Fehler, und sowas machts natürlich extrem schwer, es zu erlernen.
    Daher eins nachm anneren, nicht alles gleichzeitig.
    Ok, habe mir deine Anleitung: Daten laden, speichern, verarbeiten - einfachste Variante nochmal angeguckt und das ganze mal selber getestet. Da du das arbeiten mit einem Dataset auch noch kurz erklärst werde ich mal damit spielen und mein aktuelles Programm nachbauen (auf xml Basis zum Test). Eine Frage hätte ich aber: Wenn ich in eine neue Zeile klicke wird die ID automatisch eingetragen (Primary Key). Sofern ich aber bei meinen anderen beiden Felder nichts eingebe wird ID dieses Datensatzes bei jedem Sortier-Vorgang um 1 erhöht. Das sieht dann etwa so aus:
    Spoiler anzeigen

    XML-Quellcode

    1. <?xml version="1.0" standalone="yes"?>
    2. <DataSet1 xmlns="[url]http://tempuri.org/DataSet1.xsd[/url]">
    3. <DataTable1>
    4. <ID>1</ID>
    5. <rfid>34534543</rfid>
    6. <usrid>34543</usrid>
    7. </DataTable1>
    8. <DataTable1>
    9. <ID>2</ID>
    10. <rfid>45654</rfid>
    11. <usrid>4564545</usrid>
    12. </DataTable1>
    13. <DataTable1>
    14. <ID>3</ID>
    15. <rfid>546</rfid>
    16. <usrid>54645645</usrid>
    17. </DataTable1>
    18. <DataTable1>
    19. <ID>4</ID>
    20. <rfid>456</rfid>
    21. <usrid>5654</usrid>
    22. </DataTable1>
    23. <DataTable1>
    24. <ID>10</ID>
    25. <rfid>546546</rfid>
    26. <usrid>45654645</usrid>
    27. </DataTable1>
    28. <DataTable1>
    29. <ID>29</ID>
    30. <rfid>234234</rfid>
    31. <usrid>32432234</usrid>
    32. </DataTable1>
    33. </DataSet1>

    Ist dies normal? Sofern ich das DGview später nur per Code verändere (so der Plan) stört mich das nicht.
    ich verstehe nicht.
    Beim Sortieren werden iwelche Primärschlüssel verändert? Wenn dem so ist, ists falsch.
    Und inwiefern "sieht das dann aus" wie das gezeigte Xml?
    Das Xml zeigt ja nur eine DataTable - stimmt was nicht mit dieser - wie wäre es denn deiner Meinung nach richtig?

    Das einzige was mir am Xml auffällt ist, dass die IDs positiv sind. Normalerweise (also solange man nicht dran rumfummelt) werden nämlich negative IDs erzeugt vom Dataset.
    Ja ich kenne nur positive Schlüssel deswegen hatte ich diese positiv gemacht. Ist das grob falsch? Ich kann es auch einfach wieder ändern, man sieht diese ja sowieso nicht.
    Also wenn ich mein DataTable an ein Datagridview binde und ins unterste Feld klicke wird bei dem ID Feld automatisch die nächste ID eingefügt. Wenn ich jetzt sortieren drücke wird diese ID um 1 erhöht. Das einzige was ich sonst an meinem DataTable geändert habe ist, dass die anderen Felder nicht gefüllt sein müssen. Am DataGridView war nichts verändert. Falls das trotzdem nicht sein sollte versuche ich es gleich nochmal mit einem leeren Projekt.

    EDIT: Wieder das Selbe. Dataset mit einem DataTable angelegt, 3 Spalten. Spalte 1 ist Primär und auf AutoIncrement = True. Table an ein Datagridview gebindet, gestartet, doppelklick ins erste Feld, dann sortiert. ID = -1 > -2 > -3 etc im ersten Feld.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Departet“ ()

    vlt. kannste die Sources zippen und anhängen? aber bitte ohne binaries.



    Das mit den negativen Schlüsseln ist eine Konvention im Zusammenhang mit hinterlegter Datenbank: Neue Datensätze generiert das Dataset negativ. Hingegen die Db generiert positive PKs, wenn der Datensatz dann dort eingespeichert wird. Dieser positive PK muss dann auch wieder ins Dataset rück-übertragen werden, sonst verwenden Db und Dts ja verschiedene PKs für denselben DS.

    Jdfs. bei negativer Erst-Generierung sieht man gleich: dieser DS wurde noch nicht an die Db gesandt.

    (Ist vlt. garnet so schlecht, dassich dir das hier im Vorgriff erklären kann, gleich klein Vorgeschmack, was auf dich zukommt, wenn dann spätermal Db dran ist.)

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

    ja, und wo verändern sich da die IDs?
    Ich kann da auf den Spaltenheader klicksen wie wolle, das sortiert um - ändert aber keine ID.

    Übrigens empfehle ich dir sehr auch das in "Datenverarbeiten" verlinkte Layout-Tutorial.
    Weil das mindeste ist ja wohl, dass du dem Grid Dockstyle.Fill gibst.

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