none
Fehler "Diesem Befehl ist bereits ein geöffneter DataReader zugeordnet, der zuerst geschlossen werden muss." bei Ausführung SQL Statement RRS feed

  • Frage

  • Hallo,

    mit dem folgenden Script lese ich Werte aus einer Tabelle aus, anhand derer ich Werte in einer anderen Aktualisiere:

    Public Sub Main()
            Dim conn As New SqlConnection("Integrated Security=True; Initial Catalog=MyCatalog; Data Source=MyServer;")
    
            Dim SQL As String = "SELECT KeyName, KeyType, KeyValue ,FieldName ,FieldType ,FieldValueWrong, FieldValueCorrect " & _
                                "FROM [MyCatalog].[dbo].[MyTable];"
            Dim cmd As SqlCommand
            Dim cmd1 As SqlCommand
            Dim rdr As SqlDataReader = Nothing
            Dim rdrUpd As VariantType = Nothing
            Dim KeyName As String
            Dim KeyType As String
            Dim KeyValue As String
            Dim FieldName As String
            Dim FieldType As String
            Dim FieldValueWrong As String
            Dim FieldValueCorrect As String
            Dim strSQL As String = ""
    
            Try
                conn.Open()
                cmd = New SqlCommand(SQL, conn)
                rdr = cmd.ExecuteReader()
                While rdr.Read()
                    KeyName = rdr("KeyName")
                    KeyType = rdr("KeyType")
                    KeyValue = rdr("KeyValue")
                    FieldName = rdr("FieldName")
                    FieldType = rdr("FieldType")
                    FieldValueWrong = rdr("FieldValueWrong")
                    FieldValueCorrect = rdr("FieldValueCorrect")
                    Debug.Print(KeyName & " " & KeyType & " " & KeyValue & " " & FieldName & " " & FieldType & " " & FieldValueWrong & " " & FieldValueCorrect)
                    strSQL = "UPDATE [MyCatalog].[dbo].[MyDestTable] SET " & FieldName & " = '" & FieldValueCorrect & "' WHERE " & FieldName & " = '" & FieldValueWrong & "'  AND " & KeyName & " = '" & KeyValue & "';"
                    cmd1 = New SqlCommand(strSQL, conn)
                    cmd1.ExecuteNonQuery()
                End While
    

    Bei der Ausführung des Update bekomme ich dann immer den oben genannten Fehler.

    Hat jemand Eine Idee, woran das liegt?
    Kann ich den Update auf eine andere Tabelle nicht in der While-Schleife machen?

    Gruß

    cheapy

    Dienstag, 1. September 2015 09:48

Antworten

  • Hi,

    die Meldung ist eindeutig (und zeigt eines der IMHO mehreren Probleme des DataReader Konstrukts).

    Du kannst eine zweite Connection erstellen und das UPDATE dann darüber absetzen.

    So oder so ist es aber sinnvoll, wenn Du keine Stringverkettung für deine SQL Statements verwendest, sondern Parameter. So, wie Du es jetzt machst, handelst Du dir ggfs. SQL Injection Probleme ein.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community

    • Als Antwort markiert Cheaptrick_la Dienstag, 1. September 2015 10:24
    Dienstag, 1. September 2015 09:57
    Moderator

Alle Antworten

  • Hi,

    die Meldung ist eindeutig (und zeigt eines der IMHO mehreren Probleme des DataReader Konstrukts).

    Du kannst eine zweite Connection erstellen und das UPDATE dann darüber absetzen.

    So oder so ist es aber sinnvoll, wenn Du keine Stringverkettung für deine SQL Statements verwendest, sondern Parameter. So, wie Du es jetzt machst, handelst Du dir ggfs. SQL Injection Probleme ein.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community

    • Als Antwort markiert Cheaptrick_la Dienstag, 1. September 2015 10:24
    Dienstag, 1. September 2015 09:57
    Moderator
  • Hi,

    und was schlägst Du vor was ich an Stelle der Stringverkettung machen soll?

    Gibt es eine bessere und trotzdem variable Lösung?

    Das Problem ist, dass ich verschiedene Abhängigkeiten (Filter) habe und auch unterschiedliche Felder aktualisieren muss.

    Was die Eindeutigkeit betrifft, ja den Text der Fehlermeldung habe ich verstanden aber nicht den Hintergrund.
    Aber Du schreibst ja es liegt am DataReader Konstrukt.
    Gibt es an dieser Stelle ebenfalls eine bessere Vorgehensweise?

    Gruß

    cheapy

    Dienstag, 1. September 2015 10:24
  • Hi,
    zum ersten Thema - Parameter anstelle Zeichenverkettung:

    In Abhängigkeit von Filteranforderungen baust Du eine SQL Anweisung zusammen und synchron dazu fügst Du die Parameter-Objekte hinzu. Da bist Du genau so variabel wie mit der Zeichenverkettung. Der Einfachheit halber kann man das in einer Methode kapseln, so dass der etwas größere Aufwand nur einmalig anfällt und von verschiedenen Stellen aufgerufen werden kann. Der Vorteil der Nutzung der Parameter-Objekte ist, dass keine SQL-Injection möglich ist.

    Zum zweiten Thema - weiderholter Aufruf des DataReaders

    Die einfachste Lösung ist die Kapselung des Zugriffes in using. Bei wiederholten Aufruf wurde der vorherige using-Scope beendet und damit ist auch die Verbindung wieder nutzbar. Wenn Du bei geöffneten DataReader einen weiteren DataReader öffnen willst (z.B. beim Lesen eingebetteter Daten), kannst Du beim SQL Server MARS einschalten.


    --
    Viele Grüsse
    Peter Fleischer (MVP, Partner)
    Meine Homepage mit Tipps und Tricks

    Dienstag, 1. September 2015 11:04
  • Hallo Peter,

    ich muss gestehen, Abschnitt 1 habe ich jetzt nicht so recht verstanden.

    Und wie schalte ich MARS ein?

    Gruß

    cheapy

    Dienstag, 1. September 2015 12:26
  • Hi,
    zu Abschnitt 1 - kann ich später mal ein Beispiel posten, habe jetzt keine Zeit.

    zu MARS - schau mal im Internet, z.B. unter Multiple Active Result Sets (MARS) in SQL Server.


    --
    Viele Grüsse
    Peter Fleischer (MVP, Partner)
    Meine Homepage mit Tipps und Tricks

    Dienstag, 1. September 2015 12:34
  • Hi,
    hier mal ein Beispiel, wie ich das lösen würde. Offen ist nur, wie mit der Länge bei Zeichenketten zu verfahren ist (z.B. nvarchar).

        Dim conString = "Integrated Security=True; Initial Catalog=MyCatalog; Data Source=MyServer;"
        Dim SQL1 As String = "SELECT KeyName, KeyType, KeyValue ,FieldName ,FieldType ,FieldValueWrong, FieldValueCorrect " &
                            "FROM [MyCatalog].[dbo].[MyTable];"
        Try
          Using conn1 As New SqlConnection(conString)
            conn1.Open()
            Using conn2 As New SqlConnection(conString)
              conn2.Open()
              Using cmd1 As New SqlCommand(SQL1, conn1)
                Using cmd2 As New SqlCommand("", conn2)
                  Dim rdr1 = cmd1.ExecuteReader()
                  While rdr1.Read()
                    cmd2.Parameters.Clear()
                    cmd2.CommandText = String.Format("UPDATE [MyCatalog].[dbo].[MyDestTable] SET {0} = @p1 WHERE {0} = @p2 AND {1} = @p3", rdr1("FieldName"), rdr1("KeyName"))
                    cmd2.Parameters.AddWithValue("@p1", [Enum].Parse(GetType(SqlDbType), rdr1("FieldType").ToString())).Value = rdr1("FieldValueCorrect")
                    cmd2.Parameters.AddWithValue("@p2", [Enum].Parse(GetType(SqlDbType), rdr1("FieldType").ToString())).Value = rdr1("FieldValueWrong")
                    cmd2.Parameters.AddWithValue("@p3", [Enum].Parse(GetType(SqlDbType), rdr1("KeyType").ToString())).Value = rdr1("KeyValue")
                    cmd2.ExecuteNonQuery()
                  End While
                End Using
              End Using
            End Using
          End Using
        Catch ex As Exception
          Dim ex1 = ex
          Dim msg As String = String.Empty
          While ex1 IsNot Nothing
            msg &= ex1.Message & vbNewLine
            ex1 = ex1.InnerException
          End While
          Console.WriteLine(msg)
        End Try


    --
    Viele Grüsse
    Peter Fleischer (MVP, Partner)
    Meine Homepage mit Tipps und Tricks

    Mittwoch, 2. September 2015 05:03