使用SqlParameter创建Order By子句

我试图将我对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); 

你真的有三个选择。

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 ; 

使用SqlCommand是防止sql注入的方法。 您更改顺序的方式与在此上下文中使用sql注入相同,因此不应允许 – params用作常量,不能用作列名或表名。

你不必连接sortBy内容只是将它用作枚举,并根据它的值连接你确定是安全的东西。 像这样:

 If(orderBy == "some_column") { selectColumn += "someColumn"; } ... 

我遇到了和你一样的问题,但是列出的解决方案无法使用,因为我的可能排序列是模型的属性之一,如果模型很大,那将意味着太多的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; } } 

此解决方案的好处是,无论我的模型如何更改,此代码都将支持按其任何属性进行排序,因此也不需要更改。

我在这里找到了一个如何做到这一点的例子

您可以在CASE结构中定义不同的排序顺序,并将它们适当地执行到您的变量值:

  SELECT CompanyName, ContactName, ContactTitle FROM Customers ORDER BY CASE WHEN @SortOrder = 1 THEN CompanyName WHEN @SortOrder = 2 THEN ContactName ELSE ContactTitle 

我自己没有测试它,但它可以工作。 你可以尝试一下。 一个明显的缺点是你必须编写所有的order-by语句。

你只是连接字符串。 一种更简单的方法是:

 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等。