簡體   English   中英

執行SqlCommand失敗,因為“字符串或二進制數據將被截斷。 語句已終止”錯誤

[英]Executing SqlCommand fails due to “string or binary data would be truncated. the statement has been terminated” error

我試圖將在DevExpress的GridView中進行的更改保存到數據庫的表中,並且能夠使用以下代碼來完成此操作:

using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings[2].ConnectionString))
{
     con.Open();
     GridView gv = sender as GridView;
     using (SqlCommand cmd = con.CreateCommand())
     {                    
          cmd.CommandText = "UPDATE dbo.tb_Alumno set " + e.Column.FieldName + " = '" + e.Value + "' where pk_alumno = " + gv.GetRowCellValue(gv.FocusedRowHandle, gv.Columns[0]);                    
          cmd.ExecuteNonQuery();                    
     }
}               

自從我添加了參數命令以防止SQL注入以來,我一直遇到這個問題。 我已經對每個參數的值進行了硬編碼,以遇到提供錯誤的參數,並且是@val參數:

using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings[2].ConnectionString))            
{
    con.Open();
    GridView gv = sender as GridView;
    using (SqlCommand cmd = con.CreateCommand())
    {                    
         #region Parameters                                        
         //cmd.CommandText = "UPDATE dbo.tb_Alumno set " + e.Column.FieldName + " = '" + e.Value + "' where pk_alumno = " + gv.GetRowCellValue(gv.FocusedRowHandle, gv.Columns[0]);
         cmd.CommandText = "UPDATE dbo.tb_Alumno set @col = @val where pk_alumno = @id";
         cmd.Parameters.AddWithValue("@col", e.Column.FieldName);                    
         cmd.Parameters.AddWithValue("@val", e.Value);
         //cmd.Parameters["@val"].SqlDbType = SqlDbType.VarChar;
         cmd.Parameters.AddWithValue("@id", gv.GetRowCellValue(gv.FocusedRowHandle, gv.Columns[0]));
         #endregion
         try
         { cmd.ExecuteNonQuery(); }
         catch (Exception xe)
         { MessageBox.Show(xe.Message); }                     
    }     
}    

我可以提供的附加信息:

  • 執行查詢時出現錯誤
  • 我正在'CellValueChanged'事件中使用DevExpress15.1中的gridview
  • 數據庫的數據類型為varchar(50),參數為nvarchar
  • 當字符串超過6個字符(甚至是“硬編碼”)時,就會出現錯誤

例如,如果我使用以下參數,它將引發相同的錯誤:
cmd.Parameters.AddWithValue("@col", "name");
cmd.Parameters.AddWithValue("@val", "More than 6 characters");
cmd.Parameters.AddWithValue("@id", 1);
這發生在所有領域

如果我將中線更改為以下內容,那么我完全沒有問題
cmd.Parameters.AddWithValue("@val", "This<7");

正如您在注釋行中所看到的,我已經嘗試匹配數據類型,但這不會引發任何錯誤並且不會更新表。 我也在其他專欄上對此進行了測試,並且有相同的基本問題。

所以我的問題是:在這種特殊情況下,應該使用哪段代碼來防止SQL插入?

這是使用使用動態sql的存儲過程的示例。 請注意,動態sql利用sp_executesql有助於防止sql注入攻擊。

SQL代碼

create PROCEDURE [dbo].[SP_DynamicUpdate]
-- Add the parameters for the stored procedure here
@col varchar(50) = null,
@val varchar(50) = null,
@id int = 0
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;

-- Insert statements for procedure here
-- declaring strings
DECLARE @SQLString nvarchar(1024);
DECLARE @ParmDefinition nvarchar(512)

    SET @SQLString =
    N'Update 
        dbo.tb_Alumno
    set 
        @col_Param = @val_Param
    where 
        pk_alumno = @id_Param'

-- creating the parameters
SET @ParmDefinition = N'@col_Param varchar(50), ';
SET @ParmDefinition = @ParmDefinition + N'@val_Param varchar(50), ';
SET @ParmDefinition = @ParmDefinition + N'@id_Param int ';

-- Executing the stored procedure
EXECUTE sp_executesql @SQLString, 
                        @ParmDefinition, 
                        @col_Param = @col, 
                        @val_Param = @val, 
                        @id_Param = @id
END

C#代碼

using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings[2].ConnectionString))            
{
    GridView gv = sender as GridView;
    using (SqlCommand cmd = new SqlCommand("dbo.SP_DynamicUpdate", con))
    {                    
        #region Parameters                                        
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.AddWithValue("@col", e.Column.FieldName);                    
        cmd.Parameters.AddWithValue("@val", e.Value);
        cmd.Parameters.AddWithValue("@id", gv.GetRowCellValue(gv.FocusedRowHandle, gv.Columns[0]));
        #endregion
         try
         { 
            con.Open();
            cmd.ExecuteNonQuery(); 
         }
         catch (Exception xe)
         { 
            MessageBox.Show(xe.Message); 
         }                     
     }     
 } 

這將增加安全性,並允許您使用不同的參數分別測試存儲過程。 您甚至可以在存儲過程調用中添加更多檢查-就像存在對列名的檢查一樣。

就您執行SQL注入攻擊的方式而言,您沒有更多的選擇。

我能夠找到解決問題的最簡單方法,如下所示:

我沒有注意到,當我在datagrid和數據庫之間創建綁定時,會自動創建tableAdapter和dataSet。 通過此鏈接作為參考,我發現適配器具有更新方法,因此我使用了信息,因此我只使用了這段代碼,它像一個魅力一樣起作用,我還添加了一行以驗證該字段,說實話,我認為不是需要。

Validate();    //Or this.Validate();
tb_AlumnoTableAdapter.Update(escuelaDataSet.tb_Alumno);

和以前一樣,我將此代碼放在“ CellValueChanged”事件下,但我假設可以將其附加到按鈕上,以使其成為保存按鈕。 感謝大家的回答,希望對我這樣的人有所幫助。

您可能還想閱讀: 如何:使用TableAdapter更新數據

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM