如何将nullable int转换为SQL Null值?

时间:2015-07-01 12:15:57

标签: c# sql-server linq-to-sql

我需要使用DataContext的ExecuteCommand方法对具有多个基础表的View执行更新。我正在使用此方法,因为在具有多个基础表的视图上执行此类操作时,已知linqToSQL的限制。

我现有的SQL语句类似于以下内容,我将newFieldID设置为空值,仅用于此帖子来说明问题。在应用程序中,newFieldID被赋予一个传递的参数,实际上可能是一个整数值;但我的问题是特定于提供的值是空类型的情况:

using (var _ctx = new MyDataContext())
{
   int? newFieldID = null;
   var updateCmd = "UPDATE [SomeTable] SET fieldID = " + newFieldID + " 
   WHERE keyID = " + someKeyID;

   try
   {
      _ctx.ExecuteCommand(updateCmd);
      _ctx.SubmitChanges();
   }
   catch (Exception exc)
   {
      // Handle the error...
   }
}

此代码将失败,原因很明显,在newFieldID为空值的情况下,updateCmd不会完成。那么如何用SQL null替换或转换CLR空值来完成语句?

我知道我可以将所有这些转移到存储过程,但我正在寻找现有方案的答案。我尝试过使用DBNull.Value,但除了将其替换为在语句中使用的newFieldID之外,只需将其放入字符串中就会破坏语句的有效性。

另外,将其括在一个引号中:

var updateCmd = "UPDATE [SomeTable] SET fieldID = '" + DBNull.Value + "'
   WHERE keyID = " + someKeyID;

将完成语句,但字段的值将转换为整数0而不是SQL null。

那么在这种情况下如何将CLR null或nullable int转换为SQL Null值呢?

4 个答案:

答案 0 :(得分:4)

正确的方法:使用ExecuteCommand var updateCmd = "UPDATE [SomeTable] SET fieldID = {0} WHERE keyID = {1}"; _ctx.ExecuteCommand(updateCmd, new [] {newFieldID, someKeyID}); 不仅接受命令文本,还接受参数数组并使用参数化查询而不是命令字符串连接:

{{1}}

它不仅会阻止你进行sql注入,而且还会为你做以下事情(来自MSDN描述):

  

如果任何一个参数为null,则将其转换为DBNull.Value。

答案 1 :(得分:1)

通常,在使用“存储过程”或“准备语句”时,可以使用“参数”来指定值。如果您有DbParameter,则可以将nullDBNull.Value分配给Value-Property或您的参数。

如果您希望在语句中使用null作为文本,只需使用SQL关键字NULL

var updateCmd = "UPDATE [SomeTable] SET fieldID = NULL WHERE keyID = " + someKeyID;

答案 2 :(得分:1)

尝试检查newFieldID == null并相应地更改语句。 像下面的东西或使用单独的if / else语句。

var updateCmd = "UPDATE [SomeTable] SET fieldID =" + (newFieldID == null ? "null" : Convert.ToString(newFieldID)) + " WHERE keyID = " + someKeyID;

答案 3 :(得分:0)

正如Andy Korneyev和其他人所指出的,参数化数组方法是使用Prepared语句时最好的,也可能是更合适的方法。由于我使用的是LinqToSQL,因此建议使用带有参数数组的第二个参数的ExecuteCommand方法,但它的用法有以下几点。

  1. 查询参数不能是System.Nullable`1 [System.Int32] []类型(我在这种情况下试图解决的主要问题)
  2. 所有参数必须属于同一类型
  3. Shankar的回答虽然很快就会变得非常冗长,因为参数的数量可能会增加。

    因此,我对该问题的解决方法涉及使用Andy和Shankar建议的参数之间的混合,通过创建一个辅助方法来处理空值,这将使用带有参数映射的SQL语句和实际参数。

    我的助手方法是:

    private static string PrepareExecuteCommand (string sqlParameterizedCommand, object [] parameterArray) 
        {
            int arrayIndex = 0;
            foreach (var obj in parameterArray)
            {
                if (obj == null || Convert.IsDBNull(obj)) 
                {
                    sqlParameterizedCommand = sqlParameterizedCommand.Replace("{" + arrayIndex + "}", "NULL"); 
                }
                else
                    sqlParameterizedCommand = sqlParameterizedCommand.Replace("{" + arrayIndex + "}", obj.ToString());
                ++arrayIndex;
            }
            return sqlParameterizedCommand;
        }
    

    所以我现在可以使用具有潜在空值的参数执行我的语句,如下所示:

    int? newFieldID = null;
    int someKeyID = 12;
    var paramCmd = "UPDATE [SomeTable] SET fieldID = {0} WHERE keyID = {1}";
    var newCmd = PrepareExecuteCommand(paramCmd, new object[] { newFieldID });
    
    _ctx.ExecuteCommand(newCmd);
    _ctx.SubmitChanges();
    

    这减轻了先前引用的两个ExecuteCommand与参数数组的限制。空值被适当地转换,对象数组可能有不同的.NET类型。

    我正在将Shankar的提案作为答案,因为它引发了这个想法,但发布了我的解决方案,因为我觉得它增加了一点灵活性。