【问题标题】:SQL statement's placeholders that is not replaced leads to "Cannot update '@columnName'; field not updateable"未替换的 SQL 语句占位符导致“无法更新 '@columnName';字段不可更新”
【发布时间】:2011-09-23 23:15:41
【问题描述】:

我正在编写一些代码更新数据库,其中包含一些占位符的 SQL 语句。但它似乎没有更新这些占位符。

我收到以下错误:

Cannot update '@columnName'; field not updateable

方法如下:

    public void updateDoctorTableField(string columnName, string newValue, string vendorNumber) {
        sqlStatement = "update Doctor set @columnName = @newValue where `VENDOR #` = @vendorNumber;";
        try {
            _command = new OleDbCommand(sqlStatement, _connection);
            _command.Parameters.Add("@columnName", OleDbType.WChar).Value = columnName;
            _command.Parameters.Add("@newValue", OleDbType.WChar).Value = newValue;
            _command.Parameters.Add("@vendorNumber", OleDbType.WChar).Value = vendorNumber;

            _command.ExecuteNonQuery();
        } catch (Exception ex) {
            processExeption(ex);
        } finally {
            _connection.Close();
        }
    }

【问题讨论】:

    标签: asp.net sql sql-server database


    【解决方案1】:

    并非查询的所有部分都是可参数化的。

    您不能参数化列的名称。这需要在您的查询文本中明确指定。

    如果这是通过用户输入发送的,则需要注意防止 SQL 注入。事实上,无论如何,最好对照已知有效列名的白名单进行检查。

    【讨论】:

    • 感谢您的即时回复。有用。那么字段名称不能参数化的原因是要对照白名单进行检查?
    • @draw - 不,这不是原因本身。语言语法只允许在某些指定位置使用参数。参数化不仅仅是一种字符串插值,您可以使用它来替换查询的任意部分。但是,每当您在运行时通过字符串连接动态组合查询时,考虑到这一限制,最好考虑采取合理的预防措施来防止 SQL 注入。
    • 好的,我明白了。那么微软不以参数化方式阻止 SQL 注入的字段名称输入的原因是什么?
    • 不知道。你得问他们!我想它实现起来会很复杂,并且不太适合当前的计划编译机制或参数的使用,因为动态 SQL 很容易解决,所以其他东西有更明显的好处。
    • This connect item is Closed - Won't Fix 所以我不会很快期待这个!
    【解决方案2】:

    语言不允许表名、列名等参数的原因与您的 C# 程序不允许在代码中替换变量的原因完全相同。基本上你的问题可以在 C# 程序中改写成这样:

    class MyClass
    {
        int x;
        float y;
        string z;
    
    
        void DoSomething(string variableName)
        {
            this.@variable = ...
        }
    }
    
    MyCLass my = new MyClass();
    my.DoSomething("x"); // expect this to manuipulate my.x
    my.DoSomething("y"); // expect this to manuipulate my.y
    my.DoSomething("z"); // expect this to manuipulate my.z
    

    这显然不会编译,因为编译器无法生成代码。 T-SQL 也是如此:在您的情况下,编译器无法生成代码来定位列 "@columnName"。就像在 C# 中你会使用反射来做这种技巧一样,在 T-SQL 中你会使用动态 SQL 来实现同样的效果。

    在构建动态 SQL 以防止 SQL 注入时,您可以(并且应该)使用 QUOTENAME 函数。

    【讨论】:

      猜你喜欢
      • 2012-03-20
      • 2019-06-04
      • 1970-01-01
      • 1970-01-01
      • 2019-02-06
      • 2012-02-19
      • 1970-01-01
      • 2016-08-11
      • 2013-02-06
      相关资源
      最近更新 更多