3

我正在 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。IE

var sqlCmdStr = string.Format("SELECT NEXT VALUE FOR {0}", name);

我知道这通常是不好的做法(即 SQL 注入)。

有人会建议什么?

4

4 回答 4

5

我知道这通常是不好的做法(即 SQL 注入)。

并非每个动态 SQL 都是邪恶的。

您是否愿意接受 SQL 注入取决于值(插入到 SQL 文本中)的来源。如果它来自您的代码严格控制的地方(例如switch,从一组字符串常量中选择的语句),那么 SQL 注入就不是问题。

或者,您可以简单地对每个序列进行单独的查询(假设您没有很多)。

于 2013-01-08T17:40:05.387 回答
2

我的建议是结合@Gserg 的答案和您当前的解决方案。VARCHAR编写一个带有参数@Name的存储过程。QUOTENAME按照@GSerg 的建议,在存储过程中构建 sql 字符串。使用EXECsp_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
于 2013-01-08T17:56:53.767 回答
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
*/
于 2016-07-25T13:54:00.287 回答
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))
{
    ...
}

或者创建一个执行相同操作的服务器端过程。

于 2013-01-08T17:38:46.310 回答