繁体   English   中英

如何将可为空的 int 转换为 SQL Null 值?

[英]How to convert nullable int to SQL Null value?

我需要使用 DataContext 的 ExecuteCommand 方法对具有多个基础表的视图执行更新。 我使用这种方法是因为在具有多个基础表的视图上执行此类操作时 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 空值替换或转换 CLR 空值来完成语句呢?

我知道我可以将所有这些移动到存储过程,但我正在寻找现有场景的答案。 我曾尝试使用 DBNull.Value 进行试验,但除了将其替换为 newFieldID 以在语句中使用的挑战之外,简单地将其放入字符串中会破坏语句的有效性。

此外,将其括在单引号中:

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

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

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

正确的做法:使用ExecuteCommand 覆盖不仅接受命令文本,还接受参数数组,并使用参数化查询而不是命令字符串连接:

var updateCmd = "UPDATE [SomeTable] SET fieldID = {0} WHERE keyID = {1}";
_ctx.ExecuteCommand(updateCmd, new [] {newFieldID, someKeyID});

它不仅会阻止您进行 sql 注入,还会为您执行以下操作(来自 MSDN 描述):

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

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

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

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

尝试检查 newFieldID == null 并相应地更改语句。 类似于下面的内容或使用单独的 if / else 语句。

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

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

  1. 查询参数不能是 System.Nullable`1[System.Int32][] 类型(在这种情况下我试图解决的主要问题)
  2. 所有参数的类型必须相同

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 的提议标记为答案,因为它引发了这个想法,但发布了我的解决方案,因为我认为它增加了更多的灵活性。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM