参数化查询不起作用

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();