我正在尝试SQL Server中的SEQUENCE对象,并通过指定序列名称来获取C#的下一个值。范围很简单,因为它们有一个存储过程,您可以传递序列名称;
public static T Reserve<T>(string name, int count, SqlConnection sqlConn)
{
using (var sqlCmd = new SqlCommand("sp_sequence_get_range", sqlConn))
{
sqlCmd.CommandType = CommandType.StoredProcedure;
var firstValueParam = new SqlParameter("@range_first_value", SqlDbType.Variant) { Direction = ParameterDirection.Output };
sqlCmd.Parameters.AddWithValue("@sequence_name", name);
sqlCmd.Parameters.AddWithValue("@range_size", count);
sqlCmd.Parameters.Add(firstValueParam);
sqlCmd.ExecuteNonQuery();
return (T)firstValueParam.Value;
}
}
但是单身价值呢?在我看来,我可以调用上面的计数'1',或者我可以动态地构造SQL。即。
var sqlCmdStr = string.Format("SELECT NEXT VALUE FOR {0}", name);
我知道这通常是不好的做法(即SQL注入)。
有人会建议什么?
答案 0 :(得分:5)
我知道这通常是不好的做法(即SQL注入)。
并非每个动态SQL都是邪恶的。
是否对SQL注入开放取决于值(在SQL文本中插入的值)来自何处。如果它来自严密控制代码的地方(例如,从一组字符串常量中选择的switch
语句),则SQL注入不是问题。
或者,您可以简单地为每个序列分别设置一个查询(假设您没有很多序列)。
答案 1 :(得分:2)
我的建议是@Gserg的回答和您当前的解决方案的组合。编写一个带有VARCHAR
参数@Name的存储过程。根据@GSerg的建议,使用QUOTENAME
在存储过程中构建sql字符串。使用EXEC
或sp_executesql
运行脚本。
像这样(徒手):
CREATE PROCEDURE [GetNext]
@Name VARCHAR(50)
AS
BEGIN
DECLARE @sql VARCHAR(200);
SET @Name = QUOTENAME(@Name, '[');
SET @sql = 'SELECT NEXT VALUE FOR ' + @Name;
EXEC (@sql);
END
答案 2 :(得分:1)
Paul解决方案的另一个版本,它将从SQL序列返回格式化的字母数字键
CREATE PROCEDURE [sp_GetNextKey]
@Name NVARCHAR(50),
@FormatText NVARCHAR(50)
AS
--DECLARE @Name NVARCHAR(50)='CustomerKeySequence'
--DECLARE @FormatText NVARCHAR(50) = 'CUS0000#'
DECLARE @sql NVARCHAR(200) = 'SELECT FORMAT((NEXT VALUE FOR ' + QUOTENAME(@Name, '"') + '),'+QUOTENAME(@FormatText, '''')+')';
EXEC (@sql)
/*
RETURNS i.e CUS00184
*/
答案 3 :(得分:0)
当我需要做类似的事情时,我会这样做:
string sanitized_name;
using (var sqlCmd = new SqlCommand("select quotename(@unsafe_name, '[');", sqlConn))
{
sqlCmd.Parameters.AddWithValue("@unsafe_name", name);
sanitized_name = (string)sqlCmd.ExecuteScalar();
}
using (var sqlCmd = new SqlCommand(string.Format("select next value for {0};", sanitized_name), sqlConn))
{
...
}
或者创建一个执行相同操作的服务器端过程。