C# 由于“错误”,执行SqlCommand失败;字符串或二进制数据将被截断。本声明已被终止;错误

C# 由于“错误”,执行SqlCommand失败;字符串或二进制数据将被截断。本声明已被终止;错误,c#,gridview,sql-update,devexpress,sql-injection,C#,Gridview,Sql Update,Devexpress,Sql Injection,我正在尝试将在DevExpress的GridView中所做的更改保存到数据库的一个表中,并且我能够使用以下代码完成此操作: using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings[2].ConnectionString)) { con.Open(); GridView gv = sender as GridView; using (SqlCommand c

我正在尝试将在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”,“超过6个字符”)
cmd.Parameters.AddWithValue(“@id”,1)
所有字段都会发生这种情况

如果我将中间行更改为以下内容,我一点问题都没有

cmd.Parameters.AddWithValue(“@val”,“This下面是一个使用动态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
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); 
         }                     
     }     
 } 
C#代码

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
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注入攻击而言,您已经无能为力了。

下面是一个使用动态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
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); 
         }                     
     }     
 } 
C#代码

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
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被自动创建。作为参考,我发现适配器有一个更新方法,所以我使用了该信息,所以我简单地使用了该代码,它像一个符咒一样工作,老实说,我还添加了一行来验证字段wich我认为这是不必要的

Validate();    //Or this.Validate();
tb_AlumnoTableAdapter.Update(escuelaDataSet.tb_Alumno);
和以前一样,我将此代码放在“CellValueChanged”事件下,但我假设我可以将其设置为一个按钮,使其成为一个保存按钮。感谢大家的回答,我希望这对像我一样的其他人有所帮助


您可能还想阅读:。

我找到了解决问题的最简单方法,如下所示:

我没有注意到,当我在datagrid和数据库之间创建绑定时,一个tableAdapter和dataSet被自动创建。作为参考,我发现适配器有一个更新方法,所以我使用了该信息,所以我简单地使用了该代码,它像一个符咒一样工作,老实说,我还添加了一行来验证字段wich我认为这是不必要的

Validate();    //Or this.Validate();
tb_AlumnoTableAdapter.Update(escuelaDataSet.tb_Alumno);
和以前一样,我将此代码放在“CellValueChanged”事件下,但我假设我可以将其设置为一个按钮,使其成为一个保存按钮。感谢大家的回答,我希望这对像我一样的其他人有所帮助


您可能还想阅读:。

我很惊讶它能工作。我不认为可以将列名作为“参数”。您能看到数据库中实际运行的是什么吗?您是否考虑过创建一个调用动态sql的存储过程?我没有考虑过存储过程@dpiment,我只是觉得这样做更容易,但我确实这么做了不需要这样做,所以最好能得到最好的解决方案。(顺便说一句,我将在不久的将来尝试存储过程)@bowlturner我似乎不完全理解你的问题,你能说得更具体一点吗?(也许我不明白你说的话)我很惊讶它能工作。我不认为你可以将列名作为“参数”。你能看到数据库中实际运行的是什么吗?你有没有想过制作一个调用动态sql的存储过程?我没有想过Storage Procedures@dpimeter,我只是觉得这样做更容易,但我不需要,所以这将是非常棒的为了得到最好的解决方案。(我将在不久的将来尝试存储过程)@bowlturner我似乎不完全理解你的问题,你能再具体一点吗?(也许我不明白你说的话)当我的问题得到解决时,我会将答案标记为正确,谢谢你的答案,我正在尝试这种方法。当我的问题得到解决时,我会将答案标记为正确,谢谢你的答案,我正在尝试这种方法