在 C# 中构建具有多个参数的高效 SQL 语句
Build efficient SQL statements with multiple parameters in C#
我有一个包含不同 ID 的项目列表,这些 ID 代表 SQL table 的 PK 值。
有什么方法可以建立一个高效安全的声明吗?
从现在开始,我一直准备一个表示语句的字符串,并在通过 foreach 循环遍历列表时构建它。
这是我正在做的一个例子:
string update = "UPDATE table SET column = 0 WHERE";
foreach (Line l in list)
{
update += " id = " + l.Id + " OR";
}
// To remove last OR
update.Remove(update.Length - 3);
MySqlHelper.ExecuteNonQuery("myConnectionString", update);
感觉很不安全,也很难看。
有更好的方法吗?
使用IN运算符效率会更高:
string update = "UPDATE table SET column = 0 WHERE id IN (";
foreach (Line l in list)
{
update += l.Id + ",";
}
// To remove last comma
update.Remove(update.Length - 1);
// To insert closing bracket
update += ")";
是的,在 SQL 中,您有 'IN' 关键字,它允许您指定一组值。
这应该可以完成您想要的(语法可能有问题,但想法是存在的)
var ids = string.Join(',', list.Select(x => x.Id))
string update = $"UPDATE table SET column = 0 WHERE id IN ({ids})";
MySqlHelper.ExecuteNonQuery("myConnectionString", update);
但是,您执行 SQL 的方式可能被认为是危险的(您应该没问题,因为这看起来就像来自数据库的 ID,谁知道呢,安全总比后悔好)。在这里,您将参数直接传递到查询字符串中,这是 SQL 注入的潜在风险,非常危险。有很多方法可以解决这个问题,并使用内置的 .NET 'SqlCommand' 对象
如果使用 .NET Core Framework,请参阅以下内容 library,它为 WHERE IN 创建参数。该库是我 4.7 年前在 Framework 中编写的 VB.NET 的一个端口。克隆存储库,获取 SqlCoreUtilityLibrary
用于创建语句的项目。
设置.
public void UpdateExample()
{
var identifiers = new List<int>() { 1, 3,20, 2, 45 };
var (actual, exposed) = DataOperations.UpdateExample(
"UPDATE table SET column = 0 WHERE id IN", identifiers);
Console.WriteLine(actual);
Console.WriteLine(exposed);
}
刚好足以创建参数化 SQL 语句的代码。注意 ActualCommandText method 用于开发,而不用于生产,因为它揭示了参数的实际值。
public static (string actual, string exposed) UpdateExample(string commandText, List<int> identifiers)
{
using var cn = new SqlConnection() { ConnectionString = GetSqlConnection() };
using var cmd = new SqlCommand() { Connection = cn };
cmd.CommandText = SqlWhereInParamBuilder.BuildInClause(commandText + " ({0})", "p", identifiers);
cmd.AddParamsToCommand("p", identifiers);
return (cmd.CommandText, cmd.ActualCommandText());
}
For a real app all code would be done in the method above rather than returning the two strings.
结果
UPDATE table SET column = 0 WHERE id IN (@p0,@p1,@p2,@p3,@p4)
UPDATE table SET column = 0 WHERE id IN (1,3,20,2,45)
我有一个包含不同 ID 的项目列表,这些 ID 代表 SQL table 的 PK 值。 有什么方法可以建立一个高效安全的声明吗?
从现在开始,我一直准备一个表示语句的字符串,并在通过 foreach 循环遍历列表时构建它。
这是我正在做的一个例子:
string update = "UPDATE table SET column = 0 WHERE";
foreach (Line l in list)
{
update += " id = " + l.Id + " OR";
}
// To remove last OR
update.Remove(update.Length - 3);
MySqlHelper.ExecuteNonQuery("myConnectionString", update);
感觉很不安全,也很难看。
有更好的方法吗?
使用IN运算符效率会更高:
string update = "UPDATE table SET column = 0 WHERE id IN (";
foreach (Line l in list)
{
update += l.Id + ",";
}
// To remove last comma
update.Remove(update.Length - 1);
// To insert closing bracket
update += ")";
是的,在 SQL 中,您有 'IN' 关键字,它允许您指定一组值。
这应该可以完成您想要的(语法可能有问题,但想法是存在的)
var ids = string.Join(',', list.Select(x => x.Id))
string update = $"UPDATE table SET column = 0 WHERE id IN ({ids})";
MySqlHelper.ExecuteNonQuery("myConnectionString", update);
但是,您执行 SQL 的方式可能被认为是危险的(您应该没问题,因为这看起来就像来自数据库的 ID,谁知道呢,安全总比后悔好)。在这里,您将参数直接传递到查询字符串中,这是 SQL 注入的潜在风险,非常危险。有很多方法可以解决这个问题,并使用内置的 .NET 'SqlCommand' 对象
如果使用 .NET Core Framework,请参阅以下内容 library,它为 WHERE IN 创建参数。该库是我 4.7 年前在 Framework 中编写的 VB.NET 的一个端口。克隆存储库,获取 SqlCoreUtilityLibrary
用于创建语句的项目。
设置.
public void UpdateExample()
{
var identifiers = new List<int>() { 1, 3,20, 2, 45 };
var (actual, exposed) = DataOperations.UpdateExample(
"UPDATE table SET column = 0 WHERE id IN", identifiers);
Console.WriteLine(actual);
Console.WriteLine(exposed);
}
刚好足以创建参数化 SQL 语句的代码。注意 ActualCommandText method 用于开发,而不用于生产,因为它揭示了参数的实际值。
public static (string actual, string exposed) UpdateExample(string commandText, List<int> identifiers)
{
using var cn = new SqlConnection() { ConnectionString = GetSqlConnection() };
using var cmd = new SqlCommand() { Connection = cn };
cmd.CommandText = SqlWhereInParamBuilder.BuildInClause(commandText + " ({0})", "p", identifiers);
cmd.AddParamsToCommand("p", identifiers);
return (cmd.CommandText, cmd.ActualCommandText());
}
For a real app all code would be done in the method above rather than returning the two strings.
结果
UPDATE table SET column = 0 WHERE id IN (@p0,@p1,@p2,@p3,@p4)
UPDATE table SET column = 0 WHERE id IN (1,3,20,2,45)