使用ADO.NET和AddWithValue()处理空值

时间:2020-03-05 18:54:13  来源:igfitidea点击:

我有一个控件,可以在回发时将表单结果保存回数据库。它通过遍历查询字符串来填充要保存的值。因此,对于以下SQL语句(为便于讨论,已大大简化)...

UPDATE MyTable
SET MyVal1 = @val1,
    MyVal2 = @val2
WHERE @id = @id

...因此将循环遍历querystring键:

For Each Key As String In Request.QueryString.Keys
    Command.Parameters.AddWithValue("@" & Key, Request.QueryString(Key))
Next

但是,我现在遇到一种情况,在某些情况下,其中某些变量可能不存在于查询字符串中。如果我没有在查询字符串中传递val2,则会收到错误消息:`System.Data.SqlClient.SqlException:必须声明标量值" @ val2"。

尝试检测SQL语句中的缺失值...

IF @val2 IS NOT NULL
UPDATE MyTable
SET MyVal1 = @val1,
    MyVal2 = @val2
WHERE @id = @id

... 失败了。

最好的攻击方法是什么?我是否必须使用RegEx解析SQL块,扫描查询字符串中不存在的变量名?还是有一种更优雅的方法?

更新:在后面的VB代码中检测空值无法实现将代码与其上下文分离的目的。我宁愿不要为可能传递或者未传递的每个可能的变量提供条件。

解决方案

回答

首先,我建议不要在querystring上添加所有条目作为参数名称,我不确定这是不安全的,但我不会抓住这个机会。

问题是你在打电话

Command.Parameters.AddWithValue("@val2", null)

与此相反,我们应该致电:

If MyValue Is Nothing Then
    Command.Parameters.AddWithValue("@val2", DBNull.Value)
Else
    Command.Parameters.AddWithValue("@val2", MyValue)
End If

回答

更新:我给出的解决方案基于它是存储过程的假设。
将SQL Stored proc参数的默认值设置为Null是否可行?

如果它是动态sql,则始终传递正确数量的参数,无论它为null还是实际值或者指定默认值。

回答

我喜欢使用AddWithValue方法。

我总是为"可选"参数指定默认的SQL参数。这样,如果它为空,则ADO.NET将不包含该参数,并且存储过程将使用其默认值。

我不必以这种方式处理检查/传递DBNull.Value的问题。

回答

在努力寻找一个更简单的解决方案之后,我放弃了并写了一个例程来解析我的SQL查询中的变量名:

Dim FieldRegEx As New Regex("@([A-Z_]+)", RegexOptions.IgnoreCase)
Dim Fields As Match = FieldRegEx.Match(Query)
Dim Processed As New ArrayList

While Fields.Success
    Dim Key As String = Fields.Groups(1).Value
    Dim Val As Object = Request.QueryString(Key)
    If Val = "" Then Val = DBNull.Value
    If Not Processed.Contains(Key) Then
        Command.Parameters.AddWithValue("@" & Key, Val)
        Processed.Add(Key)
    End If
    Fields = Fields.NextMatch()
End While

这有点骇人听闻,但它使我可以使自己的代码完全不了解SQL查询的上下文。