代码之家  ›  专栏  ›  技术社区  ›  Skitzafreak

形式参数“@response”未声明为输出参数,但实际参数传入请求的输出

  •  1
  • Skitzafreak  · 技术社区  · 7 年前

    this 问题。不,它没有解决我的问题。

    我正在VB.Net中开发一个与SQL Server数据库接口的应用程序。目前,我正在尝试让VB.Net应用程序在数据库上执行以下存储过程:

    CREATE PROCEDURE dbo.AddSupplierAddress(
        @Supplier VARCHAR(100),
        @Street   VARCHAR(100),
        @City     VARCHAR(50),
        @Region   VARCHAR(50),
        @Code     VARCHAR(7),
        @Info     VARCHAR(500) = NULL,
        @response NVARCHAR(500) = OUTPUT
    ) AS
    BEGIN
        DECLARE @SupplierID INT, @RegionID INT
        SELECT @SupplierID = supplier_id
          FROM suppliers
         WHERE supplier_name = @Supplier
        IF @SupplierID IS NULL
        BEGIN
            SET @response = 'Could not add address to Supplier "' + @Supplier + '".  Supplier does not exist.'
            RETURN
        END
        SELECT @RegionID = region_id
          FROM regions
         WHERE region_name = @Region
        IF @RegionID IS NULL
        BEGIN
            SET @response = 'Could not add address to Supplier "' + @Supplier + '". Region "' + @Region + '" does not exist.'
            RETURN
        END
        IF(EXISTS(SELECT supplier_id, street FROM supplier_addresses WHERE supplier_id = @SupplierID AND street = @Street))
        BEGIN
            SET @response = 'Could not add address to Supplier "' + @Supplier + '".  Address already exists in database.'
            RETURN
        END
        BEGIN TRANSACTION AddSuppAddr
        BEGIN TRY
            INSERT supplier_addresses(supplier_id, street, city, region_id, zip_code, notes)
            VALUES (@SupplierID, @Street, @City, @RegionID, @Code, @Info)
            COMMIT TRANSACTION AddSuppAddr
            SET @response = 'Success'
        END TRY
        BEGIN CATCH
            ROLLBACK TRANSACTION AddSuppAddr
            DECLARE @varErrorMessage NVARCHAR(4000), @varErrorSeverity INT, @varErrorState INT;
            SELECT @varErrorMessage = ERROR_MESSAGE(), @varErrorSeverity = ERROR_SEVERITY(), @varErrorState = ERROR_STATE();
            RAISERROR(@varErrorMessage, @varErrorSeverity, @varErrorState);
        END CATCH
    END
    GO
    

    现在,我已使用以下方法在数据库本身上运行此过程:

    DECLARE @Resp NVARCHAR(500)
    EXEC AddSupplierAddress 'Test Name', '123 main st.', 'Hamilton', 'Ontario', 'L84B5N', NULL, @Resp
    PRINT @Resp
    

    这个程序很有效(我遇到的一个小问题是 @Resp 在数据库上测试这些过程时从不将其设置为我的输出值,但这是另一个我不想在这里解决的问题)。在我的VB.Net程序中,我尝试使用以下代码运行此过程:

    Private Sub CreateBtn_Click(sender As Object, e As EventArgs) Handles createBtn.Click
        If CreateSupplier(supplierTxt.Text, websiteTxt.Text, True) Then
            Dim message As String = ""
            If setAddress Then
                If AddSupplierAddress(supplierTxt.Text, streetTxt.Text, cityTxt.Text, regionTxt.Text, codeTxt.Text, infoTxt.Text, True) Then
                    message = "Supplier and address have been added to the database."
                Else
                    DeleteSupplier(supplierTxt.Text)
                    Return
                End If
            Else
                message = "Supplier has been added to the database."
            End If
            If MessageBox.Show(message & vbCrLf & "Would you like to add any Contacts?", "Data Added", MessageBoxButtons.YesNo) = DialogResult.Yes Then
                Dim contact As New NewContactForm(supplierTxt.Text, False, True) With {
                    .MdiParent = MdiParent
                }
                contact.Show()
            End If
        End If
    End Sub
    
    Public Function AddSupplierAddress(ByVal supplier As String,
                                       ByVal street As String,
                                       ByVal city As String,
                                       ByVal region As String,
                                       ByVal code As String,
                                       Optional info As String = "",
                                       Optional displayError As Boolean = False) As Boolean
        Dim errorMsg As String = ""
        Dim CMD As New SqlCommand("AddSupplierAddress")
        CMD.Parameters.Add("@Supplier", SqlDbType.VarChar).Value = supplier
        CMD.Parameters.Add("@Street", SqlDbType.VarChar).Value = street
        CMD.Parameters.Add("@City", SqlDbType.VarChar).Value = city
        CMD.Parameters.Add("@Region", SqlDbType.VarChar).Value = region
        CMD.Parameters.Add("@Code", SqlDbType.VarChar).Value = code
        If Not info.Equals("") Then CMD.Parameters.Add("@Info", SqlDbType.VarChar).Value = info
        If ExecuteCMDWithReturnValue(CMD, errorMsg) Then
            Return True
        Else
            If displayError Then
                MessageBox.Show(errorMsg, "Database Error")
                Return False
            Else
                Return False
            End If
        End If
    End Function
    
    Public Function ExecuteCMDWithReturnValue(ByRef CMD As SqlCommand, ByRef errorMessage As String) As Boolean
        Try
            OpenDBConnection()
            CMD.Parameters.Add("@response", SqlDbType.NVarChar, 500).Direction = ParameterDirection.Output
            CMD.Connection = DB_CONNECTION
            CMD.CommandType = CommandType.StoredProcedure
            CMD.ExecuteNonQuery()
            Dim result As String = CMD.Parameters("@response").Value
            If result.Equals("Success") Then
                ExecuteCMDWithReturnValue = True
            Else
                errorMessage = result
                ExecuteCMDWithReturnValue = False
            End If
        Catch ex As Exception
            Throw New Exception("Database Error: " & ex.Message)
            ExecuteCMDWithReturnValue = False
        Finally
            CloseDBConnection()
        End Try
    End Function
    

    如前所述,当我在数据库上运行存储过程时,不会出现此错误。更奇怪的是,我还有另一套程序,它们的编码完全相同,唯一的区别是 supplier 替换为 customer

    我得到的具体错误在标题中,但您不必向上滚动它的:

    形式参数“@response”未声明为输出参数,但实际参数传入了请求的输出。

    是什么导致了我的问题?

    1 回复  |  直到 6 年前
        1
  •  5
  •   Jeroen Mostert    7 年前

    恭喜你,你遇到了一个讨厌的T-SQL。它“允许”字符串参数默认值不带引号指定,以便

    @response NVARCHAR(500) = OUTPUT
    

    实际上相当于

    @response NVARCHAR(500) = 'OUTPUT'
    

    @response NVARCHAR(500) OUTPUT
    

    这一点尤其糟糕,因为默认值只允许常量,而不允许函数或表达式,而且引号是可选的,这会导致一些真正的误导性声明:

    @from DATETIME = GETDATE
    

    只有在调用过程而不指定 @from :此时字符串 'GETDATE' 将转换为 DATETIME (当然,这是失败的)。