我试图将我对SQL语句中的变量的所有引用移动到SqlParameter类,但由于某种原因,此查询失败。
string orderBy = Request.QueryString["OrderBy"];
//Fix up the get vars
if (orderBy == null)
orderBy = "name ASC";
string selectCommand = "SELECT cat_id AS id, cat_name AS name FROM table_name ORDER BY @OrderBy";
SqlCommand cmd = new SqlCommand(selectCommand, dataConnection);
cmd.Parameters.Add(new SqlParameter("@OrderBy", orderBy));
//Create the SQLDataAdapter instance
SqlDataAdapter dataCommand = new SqlDataAdapter(cmd);
//Create the DataSet instance
DataSet ds = new DataSet();
//Get data from a server and fill the DataSet
dataCommand.Fill(ds);
这是错误
System.Data.SqlClient.SqlException:由ORDER BY编号1标识的SELECT项包含一个变量,作为标识列位置的表达式的一部分。只有在引用列名的表达式进行排序时,才允许使用变量。
这行失败了。
dataCommand.Fill(ds);
答案 0 :(得分:14)
你真的有三种选择。
1)使用数据视图订购结果集
2)如果你知道可以订购的列,你可以测试字符串,然后使用然后选择订单。例如
例如,这将起作用
DECLARE @orderby varchar(255)
SET @orderby = 'Name ASC'
SELECT [Your Column here ]FROM sys.tables
ORDER BY
case WHEN @orderby = 'Name ASC' Then name ELSE null END ASC,
case WHEN @orderby = 'Name DESC' Then name ELSE null END DESC,
CASE WHEN @orderby = 'Object_id ASC' then object_id ELSE null END ASC,
CASE WHEN @orderby = 'Object_id DESC' then object_id ELSE null END DESC
3)最后一个选项与#2相同,但在C#代码中。请确保您不仅仅是从用户输入中添加ORDER BY子句,因为这对于SQL注入是有效的。
这是安全的,因为OrderBy Url参数"Name Desc; DROP table Users"
将被忽略
string SafeOrderBy = "";
string orderBy = Request.QueryString["OrderBy"];
//Fix up the get vars
if (orderBy == null)
orderBy = "name ASC";
if (orderby == "name Desc")
{
SafeOrderBy == "name Desc"
}
string selectCommand = "SELECT cat_id AS id, cat_name AS name FROM table_name ORDER BY "
selectCommand += SafeOrderBy ;
答案 1 :(得分:4)
使用SqlCommand
是防止sql注入的方法。你改变顺序的方法与在这种情况下使用sql注入是一样的,所以它不应该被允许 - params用作常量,不能用作列名或表名。
你不必连接sortBy
的内容,只需将其用作枚举,并根据其值连接你确定安全的东西。像这样:
If(orderBy == "some_column")
{
selectColumn += "someColumn";
}
...
答案 2 :(得分:1)
我遇到了和你一样的问题,但是列出的解决方案无法使用,因为我的可能排序列是模型的属性之一,如果模型很大,那将意味着太多的if语句。 我对这个相关问题的解决方案是使用Reflection。类似的东西:
class MyModel {
public string MyField1 { get; set; }
public string MyField2 { get; set; }
// ...
}
//...
using System.Reflection;
// sortBy = "MyField1"
// sortDirection = "Asc";
var sql = "SELECT FROM foo WHERE bar=baz ORDER BY ";
foreach (var prop in typeof(MyModel).GetProperties())
{
if (sortBy.Equals(prop.Name))
{
sql += (prop.Name + (sortDirection.Value.Equals("Asc") ? " ASC" : " DESC"));
break;
}
}
此解决方案的好处是,无论我的模型如何更改,此代码都将支持按其任何属性进行排序,因此也不需要更改。
答案 3 :(得分:0)
我找到了一个如何执行此操作的示例here
您可以在CASE结构中定义不同的排序顺序,并将它们适当地执行到您的变量值:
SELECT CompanyName,
ContactName,
ContactTitle
FROM Customers
ORDER BY CASE WHEN @SortOrder = 1 THEN CompanyName
WHEN @SortOrder = 2 THEN ContactName
ELSE ContactTitle
我自己没有测试,但它可以工作。你可以尝试一下。一个明显的缺点是你必须编写所有的order-by语句。
答案 4 :(得分:-1)
你只是连接字符串。一种更简单的方法是:
string orderBy = "name ASC";
string selectCommand = "SELECT cat_id AS id, cat_name AS name FROM table_name ORDER BY " + orderBy;
我假设你正在这样做,因为你让调用者决定排序字段/方向,因此orderBy分开。
参数,作为倾斜提示的错误消息,将在WHERE子句中使用,例如, WHERE someColumn = @someValue
等。