Visual Studio 2019 .NET VB Web 应用程序 SQL 语法错误

Visual Studio 2019 .NET VB web application SQL syntax error

我想使用来自文本框的两个用户输入执行查询搜索,并在 Viewgrid 上显示结果,但是我想在查询中插入的参数有问题,并且出现以下错误:

ExecQuery error:
Line 1: Incorrect syntax near '.'.
Must declare the variable '@H'.

我是不是实现了一个不正确的功能,或者我是否以不正确的方式执行此操作,或者我是否只是试图错误地填充视图网格?如果有人能指出正确的方向,我将不胜感激。

这是我的 SQLControl 代码:

Public Class SQLControl
    ReadOnly DBCon As New SqlConnection()
    Private DBCmd As SqlCommand

    'DB Data
    Public DBDA As SqlDataAdapter
    Public DBDT As DataTable

    'Query Parameters
    Public Params As New List(Of SqlParameter)

    'Query Statistics
    Public RecordCount As Integer
    Public Exception As String

    'This generates a blank sqlclient class with the deafult connection string
    Public Sub New()
    End Sub

    'Allow connection string override
    Public Sub New(connectionString As String)
        DBCon = New SqlConnection(connectionString)
    End Sub

    'Execute Query Sub
    Public Sub ExecQuery(query As String)
        'Reset Query Stats
        RecordCount = 0
        Exception = ""

        Try

            DBCon.Open()

            'Create DB Command
            DBCmd = New SqlCommand(query, DBCon)

            'Load Params Into DB Command
            Params.ForEach(Sub(p) DBCmd.Parameters.Add(p))

            'Clear Param List
            Params.Clear()

            'Execute Command & Fill Dataset
            DBDT = New DataTable
            DBDA = New SqlDataAdapter(DBCmd)
            RecordCount = DBDA.Fill(DBDT)
        Catch ex As Exception
            'Capture Error
            Exception = "ExecQuery Error: " & vbNewLine & ex.Message
        Finally
            'Close Connection
            If DBCon.State = ConnectionState.Open Then DBCon.Close()
        End Try
    End Sub

    'Add Params
    Public Sub AddParam(Name As String, Value As Object)
        Dim NewParam As New SqlParameter(Name, Value)
        Params.Add(NewParam)
    End Sub

    'Error Checking 
    Public Function HasException(Optional Report As Boolean = False) As Boolean
        If String.IsNullOrEmpty(Exception) Then Return False
        If Report = True Then MsgBox(Exception, MsgBoxStyle.Critical, "Exception:")
        Return True
    End Function

End Class

这是我执行查询的按钮:

Protected Sub ExecuteButton_Click(sender As Object, e As EventArgs) Handles ExecuteButton.Click

    If StoreIDTextbox.Text.Length <= 0 Then
        MsgBox("Invalid input. Please enter both Store ID and Transaction ID.")
    End If

    If TransactionIDTextbox.Text.Length <= 0 Then
        MsgBox("Invalid input. Please enter both Store ID and Transaction ID.")
    End If

    SQL.AddParam("@H.Str_ID", Integer.Parse(StoreIDTextbox.Text))
    SQL.AddParam("@H.Tran_ID", Integer.Parse(TransactionIDTextbox.Text))

    SQL.ExecQuery("SELECT H.Emp_ID, H.Cust_ID, D.*
          FROM Transaction_Header H  
          INNER JOIN LN_Detail L ON (H.Str_ID = L.Str_ID AND H.Rgst_ID = L.Rgst_ID AND H.Tran_ID = L.Tran_ID)
          INNER Join LN_Discount D ON (L.Str_ID = D.Str_ID AND L.Rgst_ID = D.Rgst_ID AND L.Tran_ID = D.Tran_ID AND L.Tran_LN_Num = D.Tran_LN_Num)
          WHERE H.Str_ID = @H.Str_ID AND H.Tran_ID = @H.Tran_ID")

    If SQL.HasException(True) Then Exit Sub

    GridView1.DataSource = SQL.DBDT

End Sub

在你的 class 中: 我已将您的数据库对象移动到使用它们的方法中,以便可以关闭和处置它们。 Using...End Using 个积木会为您做这件事。

如果您需要记录计数,可从 DataTable.Rows.Count

获得

如果您不打算在 class 中处理异常,则不要将 Try...End Try 放在那里。拥有数据访问权 class 的要点之一是将用户界面与数据源分开。在您的数据访问中显示一个消息框 class 将 link 硬编码到用户界面。您的 class 不应绑定到 Windows 中可以显示消息框的桌面应用程序。假设您想在 Web 应用程序中使用 class。您将不得不重写 class。我把 Try...End Try 放在可以显示消息框的按钮事件(用户界面代码)中。

我没有单独处理参数,因为它确实可以保护您的数据库免受 Sql 注入。然而,这不是处理 Sql 服务器参数的最佳方式。 ADO.net 必须猜测数据类型,它可能会猜错。例如,ADO.net 将字符串视为参数的值。它指定 NVarChar 作为数据类型,但数据库中的字段实际上可能是 VarChar。现在 Sql 服务器必须暂时将字段扩展为 NVarChar 以搜索您的参数。你可以看到这是多么低效。然后考虑数值 6。它是整数还是某种类型的浮点数?

在按钮代码中,我使用 Integer.TryParse 来验证用户输入,添加 Exit Sub 以允许用户更正错误。

显然,真正的问题正如@Andrew Morton 所评论的那样。我更改了参数的名称。很多时候连接是从主键到外键,但也许您有复合键。

数据访问Class

Public Class SQLControl

    Private ConStr As String = "Your connection string"

    'Query Parameters
    Public Params As New List(Of SqlParameter)

    'This generates a blank sqlclient class with the deafult connection string
    Public Sub New()
    End Sub

    'Allow connection string override
    Public Sub New(connectionString As String)
        ConStr = connectionString
    End Sub

    'Execute Query Sub
    Public Function ExecQuery(query As String) As DataTable
        'Params.Clear()
        Dim DBDT = New DataTable
        Using DBCon As New SqlConnection(ConStr),
                DBCmd As New SqlCommand(query, DBCon)
            Params.ForEach(Sub(p) DBCmd.Parameters.Add(p))
            Params.Clear()
            DBCon.Open()
            DBDT.Load(DBCmd.ExecuteReader)
        End Using
        Return DBDT
    End Function

    'Add Params
    Public Sub AddParam(Name As String, Value As Object)
        Dim NewParam As New SqlParameter(Name, Value)
        Params.Add(NewParam)
    End Sub

End Class

用户界面代码

Private Sql As New SQLControl("Your connection string")

Protected Sub ExecuteButton_Click(sender As Object, e As EventArgs) Handles ExecuteButton.Click
    Dim StoreID As Integer
    Dim TransID As Integer
    If Not Integer.TryParse(StoreIDTextbox.Text, StoreID) Then
        MsgBox("Invalid input. Please enter both Store ID and Transaction ID.")
        Exit Sub
    End If

    If Not Integer.TryParse(TransactionIDTextbox.Text, TransID) Then
        MsgBox("Invalid input. Please enter both Store ID and Transaction ID.")
        Exit Sub
    End If
    Sql.AddParam("@Str_ID", StoreID)
    Sql.AddParam("@Tran_ID", TransID)
    Dim dt As DataTable
    Try
        dt = Sql.ExecQuery("SELECT H.Emp_ID, H.Cust_ID, D.*
      FROM Transaction_Header H  
      INNER JOIN LN_Detail L ON (H.Str_ID = L.Str_ID AND H.Rgst_ID = L.Rgst_ID AND H.Tran_ID = L.Tran_ID)
      INNER Join LN_Discount D ON (L.Str_ID = D.Str_ID AND L.Rgst_ID = D.Rgst_ID AND L.Tran_ID = D.Tran_ID AND L.Tran_LN_Num = D.Tran_LN_Num)
      WHERE H.Str_ID = @Str_ID AND H.Tran_ID = @Tran_ID")
    Catch ex As Exception
        MessageBox.Show(ex.Message)
        Exit Sub
    End Try
    GridView1.DataSource = dt
End Sub