【问题标题】:SQL Parameter value is getting truncatedSQL 参数值被截断
【发布时间】:2018-03-05 16:52:22
【问题描述】:

我有以下代码,它只是执行一个接受 1 个参数的存储过程。

Public Function GetData(ByVal Faccode As String, Optional ByRef s As String = "") As DataSet

    Dim params As SqlParameter() = {New SqlParameter("@aFacilityCode", SqlDbType.VarChar, ParameterDirection.Input)}

    ' Set the value
    params(0).Value = "SW29" 'Faccode

    Try
        Dim DSet As DataSet = RunProcedure("usp_FL_GetAllData", params, "ContactData")
        Return DSet
    Catch ex As Exception
        Return Nothing
    End Try

End Function

Protected Overloads Function RunProcedure( _
  ByVal storedProcName As String, _
  ByVal parameters As IDataParameter(), _
  ByVal tableName As String) _
  As DataSet

  Dim dataSet As New dataSet

  Try
    myConnection.Open()
    Dim sqlDA As New SqlDataAdapter
    sqlDA.SelectCommand = BuildQueryCommand(storedProcName, parameters)
    sqlDA.Fill(dataSet, tableName)

    Return dataSet
  Catch ex As Exception
    Return Nothing
  Finally
    If myConnection.State = ConnectionState.Open Then
      myConnection.Close()
    End If
  End Try
End Function

Private Function BuildQueryCommand( _
  ByVal storedProcName As String, _
  ByVal parameters As IDataParameter()) _
  As SqlCommand

  Dim command As New SqlCommand(storedProcName, myConnection)
  command.CommandType = CommandType.StoredProcedure

  Dim parameter As SqlParameter
  For Each parameter In parameters
    command.Parameters.Add(parameter)
  Next

  Return command

End Function

SQL 过程是这样定义的:

CREATE PROCEDURE [dbo].[usp_FL_GetAllData]
(
   @aFacilityCode VARCHAR(10)
)

当我运行该软件时,SQL Profiler 显示正在进行此调用:

exec usp_FL_GetAllData @aFacilityCode='S'

最初,我在GetData 函数中为我的参数分配值Faccode,但注意到这种奇怪的截断,这就是我现在对值进行硬编码的原因。

我唯一能想到的是 SQL 过程将参数定义为varchar(1),但它被定义为 10,所以我不知道为什么会这样。 RunProcedure 用于许多不表现出这种行为的地方。

还有什么可能导致这种情况?

【问题讨论】:

  • 你在你的过程中使用字符串连接吗?如果是这样,您是否正确地转义了任何撇号 (')?
  • fyi:ADO.Net 使用了一种称为“连接池”的功能,在尝试重用相同的连接对象时效果不佳。 RunProcedure() 方法应该为每个调用创建一个新的连接对象,并且只重复使用相同的连接字符串。这样你真的好多了。
  • @DimUser 没有撇号或任何类似的字符。预期的 SQL 应该是 exec usp_FL_GetAllData @aFacilityCode = 'SW29'
  • @JoelCoehoorn 我会调查一下,但这是一个非常古老的应用程序,我正在尝试修改,所以如果这从来不是问题,如果现在是问题,我会感到惊讶。该应用程序曾经同时使用 Oracle 和 MS SQL,因此我将 Oracle 代码删除并替换为 MS SQL 代码。
  • 您的代码显示SqlDbType.VarChar - 长度在哪里? varchar 在很多情况下默认为 varchar(1)

标签: sql-server vb.net


【解决方案1】:

要了解为什么从构造函数调用中删除参数方向可以解决问题,请查看SqlParameter 类定义的list of constructors。请注意,没有采用参数名称SqlDbTypeParameterDirection 的构造函数;您实际调用的构造函数是this one,其第三个参数是参数大小。因为ParameterDirection.Input 的后备值是 1,所以您将参数的大小显式设置为一个字符。

当您调用未明确给出大小的构造函数时,对象会根据您分配的值推断参数的大小,如documentation for that property 中所述。

【讨论】:

  • 确认;如此简单明了。不知道我怎么没有注意到这一点。旧的 Oracle 代码指定了 ParameterDirection,当我将其更改为 SqlParameter 时,它并没有抱怨该参数,所以我认为它可以保持原样。感谢您提供信息。
  • @sab669 我觉得很奇怪,尽管在这种情况下您没有遇到异常。如果我使用普通查询将某些内容插入到列中并且它不适合,我会立即得到可怕的String or binary data would be truncated. 错误。不过,在存储过程方面并没有那么多……无论如何,感谢您的回答,为我解决了。
【解决方案2】:

这会对您的代码进行一些重要的更改。它确实解决了参数长度问题,但您需要检查它是否真的有帮助。

's was not used, and ByRef is a code smell in .Net
Public Function GetData(ByVal Faccode As String) As DataSet
    Dim params As New SqlParameter("@aFacilityCode", SqlDbType.VarChar, 10)

    If String.IsNullOrEmpty(Faccode) Then Faccode = "SW29"
    params.Value = Faccode

    'Removed Try/Catch handler. It's NEVER a good idea to just swallow exceptions like that. Let the exception bubble up to higher level code that knows how to handle it.
    Return RunProcedure("usp_FL_GetAllData", "ContactData", params)    
End Function

'Note the change to SqlParameter. IDataParameter does not have a Length or Size property. That MIGHT be your problem.
'Also note the use of ParamArray... required changing the order of the arguments, but helped simplify code in the first function
Protected Overloads Function RunProcedure( _
  ByVal storedProcName As String, ByVal tableName As String, _
  ByVal ParamArray parameters() As SqlParameter) _
  As DataSet

    Dim dataSet As New dataSet 
    Using myConnection As New SqlConnection("string here"), _
          command As SqlCommand = BuildQueryCommand(storedProcName, parameters), _
          sqlDA As New SqlDataAdapter(command)

        command.Connection = myConnection
        sqlDA.Fill(dataSet, tableName) '.Fill() will open the connection for you if needed
    End Using
    Return dataSet
End Function

Private Function BuildQueryCommand( _
   ByVal storedProcName As String, _
  ByVal ParamArray parameters() As SqlParameter) _
  As SqlCommand

    Dim command As New SqlCommand(storedProcName)
    command.CommandType = CommandType.StoredProcedure

    If parameters IsNot Nothing Then command.Parameters.AddRange(parameters)    
    Return command    
End Function

请注意,这些更改可能会影响您应用程序中的其他代码,但它们很重要。

【讨论】:

  • 感谢您的努力,乔尔,但不幸的是我解决了我的问题:从 GetData 中删除 ParameterDirection.Input 解决了这个问题。我不知道为什么会修复它,但确实如此。
【解决方案3】:

GetData 的第一行改成这样:

Dim params As SqlParameter() = {New SqlParameter("@aFacilityCode", SqlDbType.VarChar, ParameterDirection.Input)}

到这里:

Dim params As SqlParameter() = {New SqlParameter("@aFacilityCode", SqlDbType.VarChar)}

解决了我的问题。我不知道为什么,如果有人知道我很想知道为什么。

【讨论】:

  • 我发布了一个单独的答案来解释这种行为。
猜你喜欢
  • 2017-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多