【问题标题】:How to use a SqlCommand Parameter to specify the schema name for a select query如何使用 SqlCommand 参数为选择查询指定架构名称
【发布时间】:2012-02-01 18:57:22
【问题描述】:

我们数据库中的 Schema 名称是动态的。为什么以下不起作用?

public void ReadVersion(string connString, string schemaName) 
{
    string selectCommand = "SELECT major FROM [@SchemaName].[version]");
    using (SqlConnection sqlConn = new SqlConnection(connString)) 
    {
        using (SqlCommand cmd = new SqlCommand(selectCommand, sqlConn)) 
        {
            sqlConn.Open();
            cmd.Parameters.AddWithValue("@SchemaName", schemaName);
            object result = cmd.ExecuteScalar();
        }
    }
}

命令执行时,参数值不被替换。这是 SqlCommand 参数的限制吗?

【问题讨论】:

    标签: c# sql-server tsql ado.net


    【解决方案1】:

    不能在纯 SQL 中执行以下操作(因此忽略所有 ADO.Net 开销):

    DECLARE @SchemaName sysname
    SET @SchemaName = 'dbo'
    SELECT major FROM @SchemaName.[version]
    

    原因很简单。在FROM 之后,SQL 想要的是一个名称。你试图给它的是一个字符串。 SQL Server 不会随机开始查看字符串内部是否与其他构造相似。

    对于您的卫生查询,假设您保持架构名称合理,只需在架构名称上使用一个简单的正则表达式,然后再信任它(例如,^[A-Z][A-Z0-9]+$ 对于大多数用途来说应该足够了)。确保使用白名单(允许的字符)而不是黑名单。

    【讨论】:

    • 感谢 Damien - 我对 SQL 的理解有所增长。我现在看到我可以通过给数据库用户(在运行时查询架构)一个 DEFAULT_SCHEMA 来使我们的代码更加优雅——因为我们为每个架构创建了一个匹配的唯一数据库用户。
    • 嗨 - 我希望我不会破坏这个线程,但是只检查 @SchemaName 和 sys.schemas 来验证它是否可行?
    【解决方案2】:

    这是 SqlCommand 参数的限制吗?

    是的,这是一个限制。在 ADO.NET 中,您不能对架构使用参数(例如表名和列名)。你最好的选择是使用字符串连接,显然你自己的注入过滤。

    【讨论】:

    • 我认为这不是SqlCommandParameter的限制。它们一开始就不是为这种用途而设计的。
    • 谢谢达林。我想使用参数,这样我就不必担心 SQL 注入。此公共方法位于库中,供其他内部项目使用。关于如何“过滤注射”的任何建议?
    • @GarethOwen,您可能希望创建一个通过的模式名称有效的测试。例如长度,不应包含 [,],",'.
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-06
    • 2017-06-05
    相关资源
    最近更新 更多