SqlDataReader - 多个连接

发布于 2024-12-11 22:04:48 字数 2655 浏览 0 评论 0原文

我在 VB.NET 中编写了一个控制台应用程序来执行一些数据库工作,并且出现了一个奇怪的运行时错误...

这是主要代码:

Sub Main(ByVal args() As String)
        Try
            user = args(0)
            batchID = args(1)

            GetBatchRevision()
            'batchRev = 1

            Dim getTestScripts As SqlCommand = New SqlCommand("GetTestScriptsInTestBatch", cs)
            getTestScripts.CommandType = CommandType.StoredProcedure

            Dim batchIDParam As SqlParameter = getTestScripts.Parameters.Add("@batchID", SqlDbType.Int, 4)
            Dim batchRevParam As SqlParameter = getTestScripts.Parameters.Add("@batchRev", SqlDbType.Int, 4)

            'batchIDParam.Value = 1
            'batchRevParam.Value = 1
            batchIDParam.Value = batchID
            batchRevParam.Value = batchRev

            Console.WriteLine(batchID & " " & batchRev)
            Console.WriteLine(cs.State)
            Console.ReadLine()

            Using cs
                cs.Open()
                Dim reader As SqlDataReader = getTestScripts.ExecuteReader(CommandBehavior.CloseConnection)

                While reader.Read()
                    Console.WriteLine("Executing Test Script " & reader("ScriptID").ToString() & " Revision " & reader("ScriptRev").ToString)
                End While

                Console.ReadLine()
            End Using

        Catch ex As Exception
        End Try
    End Sub

GetBatchRevision:

Private Sub GetBatchRevision()
    Using cs
        Dim GetNewestRev As New SqlCommand("SELECT Max(BatchRev) FROM TestBatch WHERE BatchID=" & batchID, cs)
        cs.Open()
        Dim reader As SqlDataReader = GetNewestRev.ExecuteReader(CommandBehavior.CloseConnection)
        reader.Read()

        If Not IsDBNull(reader(0)) Then
            batchRev = reader(0).ToString()
        End If
    End Using

End Sub

batchRevbatchID都是模块内的全局变量。

行为上:

  • 应用程序打印出“1”(用户输入)、“1”(数据库结果)、“0”(关闭连接的枚举)
  • 当我按 Enter 跳过第一个 时, Console.ReadLine(),应用程序直接关闭。

如果我注释掉 GetBatchRevision 并直接设置 batchRev = 1,我会得到上述结果以及“Executing Test Script 1 Revision 52”、“Executing Test Script 2 Revision 66” " 这是存储过程 GetTestScriptsInTestBatch 的预期结果。

全局变量声明如下:

Private batchID As String

Private batchRev As String

你知道为什么 GetBatchRevision() 会导致应用程序崩溃吗?就其本身而言(删除代码的存储过程部分),它执行得很好。我最初的猜测是存在一个挂起的连接,但结束“using”块应该会关闭 SQL 连接以及与该连接关联的任何打开的读取器(如前所述,cs.State 返回 0)。

I've written a console app in VB.NET to do some database work and a strange runtime error has arisen...

Here's the main code:

Sub Main(ByVal args() As String)
        Try
            user = args(0)
            batchID = args(1)

            GetBatchRevision()
            'batchRev = 1

            Dim getTestScripts As SqlCommand = New SqlCommand("GetTestScriptsInTestBatch", cs)
            getTestScripts.CommandType = CommandType.StoredProcedure

            Dim batchIDParam As SqlParameter = getTestScripts.Parameters.Add("@batchID", SqlDbType.Int, 4)
            Dim batchRevParam As SqlParameter = getTestScripts.Parameters.Add("@batchRev", SqlDbType.Int, 4)

            'batchIDParam.Value = 1
            'batchRevParam.Value = 1
            batchIDParam.Value = batchID
            batchRevParam.Value = batchRev

            Console.WriteLine(batchID & " " & batchRev)
            Console.WriteLine(cs.State)
            Console.ReadLine()

            Using cs
                cs.Open()
                Dim reader As SqlDataReader = getTestScripts.ExecuteReader(CommandBehavior.CloseConnection)

                While reader.Read()
                    Console.WriteLine("Executing Test Script " & reader("ScriptID").ToString() & " Revision " & reader("ScriptRev").ToString)
                End While

                Console.ReadLine()
            End Using

        Catch ex As Exception
        End Try
    End Sub

GetBatchRevision:

Private Sub GetBatchRevision()
    Using cs
        Dim GetNewestRev As New SqlCommand("SELECT Max(BatchRev) FROM TestBatch WHERE BatchID=" & batchID, cs)
        cs.Open()
        Dim reader As SqlDataReader = GetNewestRev.ExecuteReader(CommandBehavior.CloseConnection)
        reader.Read()

        If Not IsDBNull(reader(0)) Then
            batchRev = reader(0).ToString()
        End If
    End Using

End Sub

batchRev and batchID are both global variables within the module.

Behaviorally:

  • The app prints out "1" (user input), "1" (database result), "0" (enum of Closed connection)
  • When I press Enter to get past the first Console.ReadLine(), the app simply closes out.

If I comment out GetBatchRevision and directly set batchRev = 1, I get the above result as well as "Executing Test Script 1 Revision 52", "Executing Test Script 2 Revision 66" which are the expected results from the stored procedure GetTestScriptsInTestBatch.

The global variable declarations are as follows:

Private batchID As String

Private batchRev As String

Any ideas why GetBatchRevision() causes the app to crash? By itself (removing the stored proc part of the code), it executes just fine. My initial guess was that there was a hanging connection, but ending a "using" block is supposed to close a SQL connection as well as any open readers associated with said connection (as mentioned before, cs.State returns 0).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

极度宠爱 2024-12-18 22:04:48

您的问题在于以下几行:

 reader.Read()

 If Not IsDBNull(reader(0)) Then

reader.Read() 可能返回 false;但您尝试访问 reader(0)。繁荣!

你应该将其更改为:

IF reader.Read() AndAlso Not IsDBNull(reader(0)) Then
    '' etc
End If

Your problem is on these lines:

 reader.Read()

 If Not IsDBNull(reader(0)) Then

reader.Read() is probably returning false; yet you try to access reader(0). Boom!

You should change it to:

IF reader.Read() AndAlso Not IsDBNull(reader(0)) Then
    '' etc
End If
纵山崖 2024-12-18 22:04:48

看起来cs也是一个全局变量。这是一个坏主意。当您每次使用新连接时,.Net 数据访问效果会更好。您可能在这个应用程序中表现良好,但您正在养成一些坏习惯。相反,将连接字符串加载为全局变量,并在创建连接时使用它。

接下来,GetBatchRevision() 没有理由与全局变量对话。让它接受一个参数并返回它的结果。当然,我不能忽视 sql 注入问题,因为您将 batchid 连接到字符串的末尾。以下是修复这些错误后该函数的新版本:

Private Function GetBatchRevision(ByVal BatchID As String) As String
    Using cn As New SqlConnection(cs), _
          GetNewestRev As New SqlCommand("SELECT Max(BatchRev) FROM TestBatch WHERE BatchID= @BatchID", cn)

        GetNewestRev.Parameters.Add("@Batch", SqlDbType.Int).Value = Convert.ToInt32(BatchId)

        cn.Open()
        Return GetNewestRev.ExecuteScalar().ToString() 
    End Using

End Function

如果您在内部将 BatchRev 和 BatchID 保留为 int 而不是字符串,效果会更好。

It looks like cs is also a global variable. This is a bad idea. .Net data access works a lot better when you're using a new connection each time. You're probably fine in this app, but you're setting up some bad habits. Instead, load your connection string as a global variable and use that when creating your connections.

Next up, there's no reason for GetBatchRevision() to talk to global variables. Have it accept an argument and return it's result instead. And of course I can't overlook the sql injection issue because you concatentate the batchid to the end of your string. Here's the new version of the function after fixing those errors:

Private Function GetBatchRevision(ByVal BatchID As String) As String
    Using cn As New SqlConnection(cs), _
          GetNewestRev As New SqlCommand("SELECT Max(BatchRev) FROM TestBatch WHERE BatchID= @BatchID", cn)

        GetNewestRev.Parameters.Add("@Batch", SqlDbType.Int).Value = Convert.ToInt32(BatchId)

        cn.Open()
        Return GetNewestRev.ExecuteScalar().ToString() 
    End Using

End Function

This can get even better if you keep BatchRev and BatchID as int's rather than strings internally.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文