C# 由于“错误”,执行SqlCommand失败;字符串或二进制数据将被截断。本声明已被终止;错误
我正在尝试将在DevExpress的GridView中所做的更改保存到数据库的一个表中,并且我能够使用以下代码完成此操作: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
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我似乎不完全理解你的问题,你能再具体一点吗?(也许我不明白你说的话)当我的问题得到解决时,我会将答案标记为正确,谢谢你的答案,我正在尝试这种方法。当我的问题得到解决时,我会将答案标记为正确,谢谢你的答案,我正在尝试这种方法