INSERT 和 SELECT 语句的组合导致 VB 中的错误

Combination of INSERT and SELECT statement causes error in VB

这是我的 SQL 服务器存储过程

ALTER PROC [dbo].[insRequestVote]  
     @fkRequest     int,  
     @fkOrganisation    int,  
     @fkUser            int  
AS 
   IF NOT Exists(SELECT 1 FROM [dbo].[tblRequestVote] 
                 WHERE [fkRequest] = @fkRequest 
                   AND [fkOrganisation] = @fkOrganisation 
                   AND [fkUser] = @fkUser)
   BEGIN
       /* This user from this organisation has not yet voted for this request */ 
       INSERT INTO [dbo].[tblRequestVote] ([fkRequest], [fkOrganisation],[fkUser], [DateStamp])
       VALUES (@fkRequest, @fkOrganisation, @fkUser, GetDate());

       SELECT 
           'Inserted' AS VoteResult;
   END
   ELSE
      SELECT 'You have already voted for this SR' AS VoteResult;

当我在 T-SQL 中 运行 时,它工作得很好,例如

insRequestVote 1, 4, 23 

将 return 所需的短语。但是,当我从 VB.NET 调用存储过程时,它只将记录写入 table,但不会 return 短语。

后面的代码:

Dim ADOConn As New ADODB.Connection  
ADOConn.ConnectionString = WFConnectionString  
If (ADOConn.State <> ConnectionState.Open) Then ADOConn.Open()  
Dim ADORecSet As New ADODB.Recordset  
Dim sSql As String = ""  

Try  
    '----// Save the Vote for the SR  
    sSql = "dbo.insRequestVote " & row.Cells(0).Text & "," & row.Cells(1).Text & "," & row.Cells(2).Text
    ADORecSet = ADOConn.Execute(sSql)  

   If Not ADORecSet.EOF Then  
      If ADORecSet.Fields("VoteResult").Value = "Inserted" Then  
         gridSRs.DataBind()  
         row.Cells(4).Text = "1"  
      End If  
   End If  

   ADORecSet.Close()  
Catch GenEx As Exception  
   '----- Catch-all  
   LogAction(Session("WhoAmI"), GenEx.Message, "Error")  
Finally  
   ADOConn.Close()  
   ADOConn = Nothing  
End Try  

在 "If Not ADORecSet.EOF Then" 语句之前一切正常,它会跳转到异常行。异常消息是

Operation is not allowed when the object is closed.

我的问题是:为什么特定模式在所有情况下都有效,除非我在一个存储过程中组合了 INSERT 和 SELECT?

我们从哪里开始...您的代码充满了反模式。您应该阅读有关正确使用 ado 的内容,我们转向更简单的东西,例如 ORM。除此之外:

  1. 从不 根据用户输入动态构建要在 SQL 中执行的字符串。永远,永远,永远使用参数化查询。否则我可以从你的文本框中删除你所有的数据库表,这很简单。

  2. 由于这是一个存储过程,您应该将命令类型设置为该类型,而不是使用文本。否则这会导致 return 值出现异常,这是不好的做法。

  3. 您将其标记为 vb。 Net,但您使用的是旧式 ADO?使用 ADO。 Net which returns datasets, not long deprecated recordsets

知道了!以防万一其他人正在尝试这个,这是我修改后的代码:

Dim SQLConn As New SqlConnection(WFConnectionStringNET)
If (SQLConn.State <> ConnectionState.Open) Then SQLConn.Open()

Dim sSql As String = ""
Try
                '----// Save the Vote for the SR
                sSql = "dbo.insRequestVote " & Mid(row.Cells(0).Text, 2, InStr(row.Cells(0).Text, ":") - 2) & "," &
                                               Session("ThisUserOrganisationID") & "," &
                                               Session("ThisUserID")
                Dim sqlCmd As New SqlCommand(sSql, SQLConn)
                sqlCmd.Parameters.Add("@fkRequest", SqlDbType.Int).Value = Mid(row.Cells(0).Text, 2, InStr(row.Cells(0).Text, ":") - 2)
                sqlCmd.Parameters.Add("@fkOrganisation", SqlDbType.Int).Value = Session("ThisUserOrganisationID")
                sqlCmd.Parameters.Add("@fkUser", SqlDbType.Int).Value = Session("ThisUserID")
                Dim sqlDR As SqlDataReader = sqlCmd.ExecuteReader()

                While sqlDR.Read()
                    If sqlDR("VoteResult") = "Inserted" Then
                        gridSRs.DataBind()
                        row.Cells(4).Text = "1"
                    End If
                End While
                sqlDR.Close()

                LogAction(Session("WhoAmI"), "Voted for SR " & row.Cells(5).Text)

            Catch GenEx As Exception
                '-----// Catch-all
                LogAction(Session("WhoAmI"), GenEx.Message, "Error")
            Finally
                SQLConn.Close()
                SQLConn = Nothing
            End Try