参数化查询不起作用
Parameterized Queries not working
我用 SQL
填充 DataTable
的以下实现:
var con = new SqlConnection();
var cmd = new SqlCommand();
var dt = new DataTable();
string sSQL = @"SELECT LogID, Severity, Title
FROM dbo.Log
WHERE UPPER(LogID) LIKE '%" + searchPhrase.ToUpper() + @"%' OR UPPER(Severity) LIKE '%" + searchPhrase.ToUpper() + @"%' OR UPPER(Title) LIKE '%" + searchPhrase.ToUpper() + @"%' ORDER BY " + orderBy + " " + orderFrom + @"
OFFSET ((" + (Convert.ToInt32(current) - 1).ToString() + ") * " + rowCount + @") ROWS
FETCH NEXT " + rowCount + " ROWS ONLY;";
try
{
using (var connection = THF.Models.SQLConnectionManager.GetConnection())
{
using (var command = new SqlCommand(sSQL, connection))
{
connection.Open();
command.CommandTimeout = 0;
var da = new SqlDataAdapter(command);
da.Fill(dt);
}
}
}
catch { }
这很好用,但我意识到由于 SQL 注入,这很危险。所以我尝试使用像这样的参数化查询来解决这个危险:
var con = new SqlConnection();
var cmd = new SqlCommand();
var dt = new DataTable();
cmd.Parameters.Add(new ObjectParameter("@searchPhrase", searchPhrase.ToUpper()));
cmd.Parameters.Add(new ObjectParameter("@orderBy", orderBy));
cmd.Parameters.Add(new ObjectParameter("@orderFrom", orderFrom));
cmd.Parameters.Add(new ObjectParameter("@current", current));
cmd.Parameters.Add(new ObjectParameter("@rowCount", rowCount));
string sSQL = @"SELECT LogID, Severity, Title
FROM dbo.Log
WHERE UPPER(LogID) LIKE '%" + searchPhrase.ToUpper() + @"%' OR UPPER(Severity) LIKE '%" + searchPhrase.ToUpper() + @"%' OR UPPER(Title) LIKE '%" + searchPhrase.ToUpper() + @"%' ORDER BY " + orderBy + " " + orderFrom + @"
OFFSET ((" + (Convert.ToInt32(current) - 1).ToString() + ") * " + rowCount + @") ROWS
FETCH NEXT " + rowCount + " ROWS ONLY;";
try
{
using (var connection = THF.Models.SQLConnectionManager.GetConnection())
{
using (var command = new SqlCommand(sSQL, connection))
{
connection.Open();
command.CommandTimeout = 0;
var da = new SqlDataAdapter(command);
da.Fill(dt);
}
}
}
catch { }
不幸的是现在我的数据 table 没有填满。我做错了什么?
- 您正在使用多个命令和连接引用,不确定那是 copy/paste 问题还是您的实际代码就是这样。在第二种情况下,它甚至不会编译。
- 直接在查询中引用参数,见下文。 Sql 服务器使用命名参数,因此可以在多个位置重复使用相同的参数。
- Desc/Asc不能作为参数使用。您应该仔细检查该值,或者使用枚举并传递它(推荐)。
- rowcount 的数值也是如此,将它们作为数字传递或使用 TryParse 检查它们的值以确保它是数字而不是恶意代码。
- Sql 服务器的默认安装选项适用于不区分大小写的联合。这意味着您不必
UPPER
一个字符串来进行比较。如果您的安装确实区分大小写,则不要更改此设置,否则在进行比较时删除对 UPPER
的所有调用。
- 最后,如果您将代码包围在
try/catch
中并且有一个空的 catch
块,您将永远不知道为什么您的代码无法正常工作。您的代码将无声地失败,您将摸不着头脑。不要在代码的任何地方这样做,这是不好的做法!!捕获异常并处理它(做一些事情以便代码可以恢复)或者记录它并使用 throw;
重新抛出或者根本不捕获它。我选了后者去掉了
代码
var currentNum = Convert.ToInt32(current) - 1;
var temp = 0;
if(!"desc".Equals(orderFrom, StringComparison.OrdinalIgnoreCase) && !"asc".Equals(orderFrom, StringComparison.OrdinalIgnoreCase))
throw new ArgumentException("orderFrom is not a valid value");
if(!int.TryParse(rowCount, out temp))
throw new ArgumentException("Rowcount is not a valid number");
var dt = new DataTable();
string sSQL = @"SELECT LogID, Severity, Title
FROM dbo.Log
WHERE UPPER(LogID) LIKE @searchPhrase
OR UPPER(Severity) LIKE @searchPhrase
OR UPPER(Title) LIKE @searchPhrase
ORDER BY @orderBy " + orderFrom + "
OFFSET ((" + currentNum.ToString() + ") * " + rowCount + @") ROWS
FETCH NEXT " + rowCount + " ROWS ONLY;";
using (var connection = THF.Models.SQLConnectionManager.GetConnection())
using (var command = new SqlCommand(sSQL, connection))
{
cmd.Parameters.Add(new SqlParameter("@searchPhrase", "%" + searchPhrase.ToUpper() + "%"));
cmd.Parameters.Add(new SqlParameter("@orderBy", orderBy));
connection.Open();
command.CommandTimeout = 0;
var da = new SqlDataAdapter(command);
da.Fill(dt);
}
这里有一个简单的例子来说明如何做到这一点。
con.Open();
SqlCommand cmd = new SqlCommand(@"insert into tbl_insert values(@name,@email,@add)", con);
cmd.Parameters.AddWithValue("@name", txtname.Text);
cmd.Parameters.AddWithValue("@email", txtemail.Text);
cmd.Parameters.AddWithValue("@add", txtadd.Text);
cmd.ExecuteNonQuery();
con.Close();
我用 SQL
填充 DataTable
的以下实现:
var con = new SqlConnection();
var cmd = new SqlCommand();
var dt = new DataTable();
string sSQL = @"SELECT LogID, Severity, Title
FROM dbo.Log
WHERE UPPER(LogID) LIKE '%" + searchPhrase.ToUpper() + @"%' OR UPPER(Severity) LIKE '%" + searchPhrase.ToUpper() + @"%' OR UPPER(Title) LIKE '%" + searchPhrase.ToUpper() + @"%' ORDER BY " + orderBy + " " + orderFrom + @"
OFFSET ((" + (Convert.ToInt32(current) - 1).ToString() + ") * " + rowCount + @") ROWS
FETCH NEXT " + rowCount + " ROWS ONLY;";
try
{
using (var connection = THF.Models.SQLConnectionManager.GetConnection())
{
using (var command = new SqlCommand(sSQL, connection))
{
connection.Open();
command.CommandTimeout = 0;
var da = new SqlDataAdapter(command);
da.Fill(dt);
}
}
}
catch { }
这很好用,但我意识到由于 SQL 注入,这很危险。所以我尝试使用像这样的参数化查询来解决这个危险:
var con = new SqlConnection();
var cmd = new SqlCommand();
var dt = new DataTable();
cmd.Parameters.Add(new ObjectParameter("@searchPhrase", searchPhrase.ToUpper()));
cmd.Parameters.Add(new ObjectParameter("@orderBy", orderBy));
cmd.Parameters.Add(new ObjectParameter("@orderFrom", orderFrom));
cmd.Parameters.Add(new ObjectParameter("@current", current));
cmd.Parameters.Add(new ObjectParameter("@rowCount", rowCount));
string sSQL = @"SELECT LogID, Severity, Title
FROM dbo.Log
WHERE UPPER(LogID) LIKE '%" + searchPhrase.ToUpper() + @"%' OR UPPER(Severity) LIKE '%" + searchPhrase.ToUpper() + @"%' OR UPPER(Title) LIKE '%" + searchPhrase.ToUpper() + @"%' ORDER BY " + orderBy + " " + orderFrom + @"
OFFSET ((" + (Convert.ToInt32(current) - 1).ToString() + ") * " + rowCount + @") ROWS
FETCH NEXT " + rowCount + " ROWS ONLY;";
try
{
using (var connection = THF.Models.SQLConnectionManager.GetConnection())
{
using (var command = new SqlCommand(sSQL, connection))
{
connection.Open();
command.CommandTimeout = 0;
var da = new SqlDataAdapter(command);
da.Fill(dt);
}
}
}
catch { }
不幸的是现在我的数据 table 没有填满。我做错了什么?
- 您正在使用多个命令和连接引用,不确定那是 copy/paste 问题还是您的实际代码就是这样。在第二种情况下,它甚至不会编译。
- 直接在查询中引用参数,见下文。 Sql 服务器使用命名参数,因此可以在多个位置重复使用相同的参数。
- Desc/Asc不能作为参数使用。您应该仔细检查该值,或者使用枚举并传递它(推荐)。
- rowcount 的数值也是如此,将它们作为数字传递或使用 TryParse 检查它们的值以确保它是数字而不是恶意代码。
- Sql 服务器的默认安装选项适用于不区分大小写的联合。这意味着您不必
UPPER
一个字符串来进行比较。如果您的安装确实区分大小写,则不要更改此设置,否则在进行比较时删除对UPPER
的所有调用。 - 最后,如果您将代码包围在
try/catch
中并且有一个空的catch
块,您将永远不知道为什么您的代码无法正常工作。您的代码将无声地失败,您将摸不着头脑。不要在代码的任何地方这样做,这是不好的做法!!捕获异常并处理它(做一些事情以便代码可以恢复)或者记录它并使用throw;
重新抛出或者根本不捕获它。我选了后者去掉了
代码
var currentNum = Convert.ToInt32(current) - 1;
var temp = 0;
if(!"desc".Equals(orderFrom, StringComparison.OrdinalIgnoreCase) && !"asc".Equals(orderFrom, StringComparison.OrdinalIgnoreCase))
throw new ArgumentException("orderFrom is not a valid value");
if(!int.TryParse(rowCount, out temp))
throw new ArgumentException("Rowcount is not a valid number");
var dt = new DataTable();
string sSQL = @"SELECT LogID, Severity, Title
FROM dbo.Log
WHERE UPPER(LogID) LIKE @searchPhrase
OR UPPER(Severity) LIKE @searchPhrase
OR UPPER(Title) LIKE @searchPhrase
ORDER BY @orderBy " + orderFrom + "
OFFSET ((" + currentNum.ToString() + ") * " + rowCount + @") ROWS
FETCH NEXT " + rowCount + " ROWS ONLY;";
using (var connection = THF.Models.SQLConnectionManager.GetConnection())
using (var command = new SqlCommand(sSQL, connection))
{
cmd.Parameters.Add(new SqlParameter("@searchPhrase", "%" + searchPhrase.ToUpper() + "%"));
cmd.Parameters.Add(new SqlParameter("@orderBy", orderBy));
connection.Open();
command.CommandTimeout = 0;
var da = new SqlDataAdapter(command);
da.Fill(dt);
}
这里有一个简单的例子来说明如何做到这一点。
con.Open();
SqlCommand cmd = new SqlCommand(@"insert into tbl_insert values(@name,@email,@add)", con);
cmd.Parameters.AddWithValue("@name", txtname.Text);
cmd.Parameters.AddWithValue("@email", txtemail.Text);
cmd.Parameters.AddWithValue("@add", txtadd.Text);
cmd.ExecuteNonQuery();
con.Close();