SQLCommand Disposen

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

Es gibt 19 Antworten in diesem Thema. Der letzte Beitrag () ist von Haudruferzappeltnoch.

    SQLCommand Disposen

    Hallo,

    Die Klasse SqlCommand hat die Dispose-Methode. Ihre Instanz nimmt eine SqlConnection auf die widerum Disposed werden kann.
    Wird die SqlConnection so denn überhaupt Disposed?

    VB.NET-Quellcode

    1. Using testcmd as New SqlCommand("", New SqlConnection(""))
    2. End Using


    Oder brauche ich immer zwei Using-Blöcke egal was ich tue?

    VB.NET-Quellcode

    1. Using testconn as New SqlConnection("")
    2. Using testcmd as New SqlCommand("", testconn)
    3. End Using
    4. End Using

    So würde es auch funktionieren denke ich:

    VB.NET-Quellcode

    1. Using testcmd as New SqlCommand("", New SqlConnection(""))
    2. testcmd.Connection.Dispose
    3. End Using


    Und funktioniert sowas vielleicht zum Disposen der beiden Instanzen?

    VB.NET-Quellcode

    1. Private Function CreateSqlConnection() As SqlConnection
    2. Using conn as New SqlConnection(ConnString)
    3. Return conn
    4. End Using
    5. End Function
    6. Friend Function CreateCommand() As SqlCommand
    7. Using cmd as New SqlCommand(SqlString, CreateSqlConnection())
    8. Return cmd
    9. End Using
    10. End Function
    11. Private Sub MachwasmitCommands
    12. cmd = CreateCommand
    13. cmd = Nothing
    14. End Sub



    Viele Grüße

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

    letzteres funzt net, weil was du returnst ist dann bereits disposed.

    aber willst du wirklich für jedes Command auch ein eigenes Connection-Objekt anlegen? (und wieder disposen)

    Meine Wenigkeit benutzt immer DataAdapter, und die dispose ich garnet.
    vielleicht wechsel ich mal den Where-Abschnitt im CommandText im DataAdapter, aber stark überwiegend bin ich für Leben und leben lassen.
    Und was ist mit dem ganz ersten Beispiel? Ist da die Connection Disposed?

    Wenn ich für eine Connection mehrere Commands habe, kann ich die ja trotzdem wechseln mit .CommandText.
    Mit DataAdapter weiß ich nicht wie ich Inserts, Deletes und Updates mache, da brauche ich meist nur ExecuteNonQuery

    Da rechne ich vielleicht ein Datum im Programm aus und dann wutsch muss aus der DB nur alles vor dem Datum gestrichen werden. Da hab ich dann keine DataTable DGV, DataAdapter.

    Ich benutze aber auch DataAdapter trotzdem noch als Einweglösung, ich komm nicht dahinter wie die funktionieren. Gerade auch weil da überall Objekte hinterstecken die Disposed werden müssen. Das tue ich lieber so früh wie möglich machen.
    zB

    VB.NET-Quellcode

    1. DataAdapter.Update(dataTable)
    wie sonst?

    Aber das hättest du im ObjectBrowser auch selbst gefunden.
    Guck da mal nach - es gibt noch mehr.

    Tatsächlich habichmir umfangreiche Infrastruktur gebastelt, die für ein Dataset automatisch alle erforderlichen DataAdapter konstruiert (für jede DataTable einen), und sie auch korrekt aufruft - unter Berücksichtigung der Relationen.
    Damit ist das Updaten des kompletten Datasets - egal, ob viele oder wenige Änderungen vorliegen, und welcher Art - nur noch ein Befehl.
    Dataset->Db
    Ja das meinte ich auch eher mit meiner Frage, weil bei mir schlägt ein einzelnes DataAdapter.Update fehl, da DataAdapter.UpdateCommand nicht gegeben ist, den Befehl selbst kannte ich natürlich.

    Ok habe deinen Link nochmal durchgelesen und ja der SqlCommandBuilder ist das Ding an der Sache. Ich brauche mit dem nichts weiter machen es funktioniert einfach schon. Hatte ihn erst noch das UpdateCommand mit GetUpdateCommand übergeben lassen. Aber anscheinend macht er das von allein wenn man es selbst nicht tut und es ist auch während der Laufzeit kein UpdateCommand zu finden.

    Das muss also im Update-Befehl drinstecken.

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private da As New SqlDataAdapter
    3. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
    4. Dim DBZ As New DBZugriff("Select * from DasIstEinTest", DBZugriff.Server.ServerName1, DBZugriff.DataBase.DataBase1)
    5. Dim cmd = DBZ.CreateCommand
    6. da.SelectCommand = cmd
    7. End Sub
    8. Private Sub btnSave_Click(sender As Object, e As EventArgs) Handles btnSave.Click
    9. Using a As New SqlCommandBuilder(da)
    10. da.Update(DS1, "DasIstEinTest")
    11. End Using
    12. End Sub
    13. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    14. da.Fill(DS1, "DasIstEinTest")
    15. End Sub
    16. End Class


    Aber Fragezeichen macht das schon.

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

    warum immer einen neuen CommandBuilder?
    Einmal initialisieren und gut ist.

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private da As New SqlDataAdapter
    3. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
    4. Dim DBZ As New DBZugriff("Select * from DasIstEinTest", DBZugriff.Server.ServerName1, DBZugriff.DataBase.DataBase1)
    5. Dim cmd = DBZ.CreateCommand
    6. da.SelectCommand = cmd
    7. Dim a As New SqlCommandBuilder(da)
    8. End Sub
    9. Private Sub btnSave_Click(sender As Object, e As EventArgs) Handles btnSave.Click
    10. da.Update(DS1, "DasIstEinTest")
    11. End Sub
    12. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    13. da.Fill(DS1, "DasIstEinTest")
    14. End Sub
    15. End Class
    nicht wundern über zeile#7 - das muss tatsächlich so.
    Mit "das muss so" meinst du der CommandBuilder muss lokal deklariert werden? Gibt es dazu ein warum?

    Es funktioniert, aber Sinn macht es nicht. Hab das Gefühl nichtmal Microsoft versteht das. Die schreiben in ihrer Doku zum Builder:

    VB.NET-Quellcode

    1. builder.GetUpdateCommand()
    2. ' Without the SqlCommandBuilder this line would fail.
    3. adapter.Update(dataSet, tableName)

    Lassen aber außer acht, dass die Zeile GetUpdateCommand() offenbar keinen Unterschied macht wenn die nicht da wäre. Wie könnte man da von selbst drauf kommen, frag ich mich.

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

    Haudruferzappeltnoch schrieb:

    Mit "das muss so" meinst du der CommandBuilder muss lokal deklariert werden?
    Im Grunde nichtmal das.
    Es muss nur Sub New() aufgerufen werden, und das geht numal nicht, ohne dass man das Ding an irgendetwas zuweist. Dasjenige, woran es zugewiesen wird (a) wird garnet gebraucht.



    Haudruferzappeltnoch schrieb:

    Hab das Gefühl nichtmal Microsoft versteht das.
    Das Gefühl verstehe ich ;)
    Kann immer nur derselbe DataAdapter updaten, der auch vorher die Tabelle gefüllt hat?

    Wenn ich eine Tabelle aus mysql in mssql schieben möchte, dann nutze ich natürlich zwei unterschiedliche DataAdapter
    Einmal nen MySqlDataAdapter zum füllen und einen SqlDataAdapter zum Updaten.

    Gibt es eine Methoden die Tabelle als Ganzes zu schreiben? Oder nur zeilenweise Inserts selbst basteln?
    Das sind komische Anwendungsfälle, und wäre glaub gut, wenn du sagst, was du vorhast.
    Db-Tabellen kopieren ist problematisch wegen der autoincrement PrimaryKeys.
    Die Kopie wird andere PKs haben als die Vorlage. Fremdschlüssel untergeordneter Tabellen werden nicht mehr dazu passen.
    Also da müsste man mit SQL arbeiten, dass temporär AutoIncrement abgeschaltet wird und son kram.
    heikelheikel - wie gesagt: sag, was du vorhast.
    Also dann wird es wieder daran liegen, dass das Datenmodell nicht richtig gewählt ist, aber so ist es nun mal:

    In der ursprünglichen Tabelle befindet sich ein Ist-Stand an Daten. Das heißt Einträge werden bei bestimmten Vorgängen geändert.
    Was ich bräuchte sind historische Daten. Also ein Tabelle die jeden Ist-Stand importiert. Und somit mehrere Ist-Stände zu den jeweiligen Importzeitpunkten bereithält.

    z.B Ein Fahrzeug und ein Standort. Die Tabelle sagt dir wo das Fahrzeug jetzt ist. Ich brauche den Weg den es genommen hat.

    Also würde ich täglich den Jetztstand einfach importieren innerhalb eines Zeitraums. Dazu kommt, dass ich zwei Datenquellen habe, das eine ist meine Eigene, das Andere nicht. Meine eigene Tabelle hat gar kein AutoIncrement. Da ein Datensatz ursprünglich eindeutig ist, bleibt er durch den hinzugefügten Importzeitpunkt auch eindeutig.

    Haudruferzappeltnoch schrieb:

    Was ich bräuchte sind historische Daten. Also ein Tabelle die jeden Ist-Stand exportiert. Und somit mehrere Ist-Stände zu den jeweiligen Exportzeitpunkten bereithält.
    So nebenbei: Damit hast du ein klein Datenmodell mit einer 1:n-Relation skizziert.

    Deine exportierten Datensätze wären aber nicht mehr identisch mit ihren Quellen, weil sie müssen ja einen FK aufweisen, der auf ihren Export-Zeitpunkt verweist.
    (Oder kannst die übergeordnete Tabelle auch weglassen, indem du den Exportzeitpunkt selbst in die Export-Datensätze einträgst.)

    Jo, wenn du das nie verarbeiten willst, brauchst du diese Tabelle auch in keim typDataset.
    Also du kannst mit einer zusätzlichen typDataTable arbeiten, Datensätze codeseitig zufügen, und dann per DataAdapter an eine Db senden.

    Kannst aber auch ein einzelnes InsertCommand konfigurieren, und für jeden Datensatz gegen die Db abfeuern (intern macht der DataAdapter auch nix anneres).

    Wenn das ein PerformanceProblem ist, musste dich über "Bulk-Insert" schlau machen. Das ist ziemlich umständlich, und jede DB macht das anders, aber dafür deutlich sehr viel schneller.

    So oder so: deine Export-Datensätze sind nicht identisch mit deinen Original-Datensätzen. Die History ist eben die History, und somit eine andere Entität/Tabelle als deine "IstStandDaten" (einfacher wäre drüber zu sprechen, wenn du auch den Namen dieser Tabelle verraten tätest).
    Nagut performant ist es noch, das sind nicht allzu viele Daten.

    Ich habe schon im Select der Ist-Stände den Exportzeitpunkt drin.

    SQL-Abfrage

    1. Select Fahrzeug, Standort, current_date as ImportTS from Fahrzeugpositionen
    . Also eine Tabelle Fahrzeugpositionen habe ich nie wirklich in VB geladen, sondern nur die Änderung, die auf die HistoryFahrzeugPositionen übertragen werden müssen. Also die Tabelle die Updatet und die "echte" History Tabelle sind sich erstmal identisch, nur der Inhalt nicht.