【问题标题】:Powershell and SQL parameters. If empty string, pass DBNullPowershell 和 SQL 参数。如果为空字符串,则传递 DBNull
【发布时间】:2009-05-28 14:00:07
【问题描述】:

我得到了这个参数:

$objDbCmd.Parameters.Add("@telephone", [System.Data.SqlDbType]::VarChar, 18) | Out-Null;
$objDbCmd.Parameters["@telephone"].Value = $objUser.Telephone;

字符串$objUser.Telephone 可以为空。如果为空,如何转换为[DBNull]::Value

我试过了:

if ([string]:IsNullOrEmpty($objUser.Telephone)) { $objUser.Telephone = [DBNull]::Value };

但这给了我错误:

使用“0”参数调用“ExecuteNonQuery”的异常:“无法将参数值从 ResultPropertyValueCollection 转换为字符串。”

如果我将它转换为字符串,它会插入一个空字符串"",而不是DBNull

如何做到这一点?

谢谢。

【问题讨论】:

    标签: sql powershell dbnull


    【解决方案1】:

    在 PowerShell 中,您可以将 null/空字符串视为布尔值。

    $x = $null
    if ($x) { 'this wont print' }
    
    $x = ""
    if ($x) { 'this wont print' }
    
    $x = "blah"
    if ($x) { 'this will' }
    

    所以....话虽如此,你可以做到:

    $Parameter.Value = $(if ($x) { $x } else { [DBNull]::Value })
    

    但我更愿意将其封装在如下函数中:

    function CatchNull([String]$x) {
       if ($x) { $x } else { [DBNull]::Value }
    }
    

    【讨论】:

    • 非常有趣。谢谢乔希。我将在今天晚些时候对此进行测试,然后我会告诉你它是否解决了我的问题。
    【解决方案2】:

    我不了解 powershell,但在 C# 中我会这样做:

    if ([string]::IsNullOrEmpty($objUser.Telephone))
    {
     $objDbCmd.Parameters["@telephone"].Value = [DBNull]::Value;
    }
    else
    {
     $objDbCmd.Parameters["@telephone"].Value = $objUser.Telephone;
    }
    

    【讨论】:

    • 这在 PowerShell 中确实有效(有一个小调整 - 编辑为使用 PowerShell 语法调用静态成员)。这就是我在几个脚本中所做的,并且可以正常工作。
    • 那将是一个解决方案是的。但我希望有一个不需要那么多代码的“更简单”的解决方案。就像一个将空字符串转换为 DBNull 的函数。我有大约 60 个参数...
    【解决方案3】:

    始终在 db 值的末尾附加 +""...

    $command.Parameters["@EmployeeType"].Value= $ADResult.EmployeeType + ""

    【讨论】:

      【解决方案4】:

      多年后,让我澄清一下:

      Josh's answer 展示了一种有助于测试空字符串的简化方法(依赖于 PowerShell 的 implicit 到布尔转换[1]),但它与 Tommy 的 ( OP的)问题。

      相反,错误信息

      “将参数值从 ResultPropertyValueCollection 转换为字符串失败。”

      暗示 non-null 情况导致了问题, 因为$objDbCmd.Parameters["@telephone"].Value 需要 string 值或 @987654324 @,而$objUser.Telephone[ResultPropertyValueCollection] 类型,即值的集合

      因此,在非空情况下,必须分配一个字符串值,该值必须从集合中派生;一种选择是采用 first 集合元素的值,另一种方法是使用分隔符连接所有值以形成单个字符串,例如使用 [string]::Join(';', $objUser.Telephone) 或者,如果使用 空格是可以接受的(对于多个电话号码不是一个好主意),只需使用"$($objUser.Telephone)"[2]

      尽管类型不匹配,但通过 [string]:IsNullOrEmpty() 检测空集合实际上有效,因为 PowerShell 在将值传递给 [string] 类型化方法参数时如何隐式字符串化集合。[2]

      类似地,使用 隐式 到布尔转换也可以按预期对集合进行:空集合评估为 $false,非空集合评估为 $true(只要有至少两个元素或唯一的元素本身将被视为$true[1])

      因此,一种解决方案是使用 first 电话号码条目:

      $objDbCmd.Parameters["@telephone"].Value = if ($objUser.Telephone) {
          $objUser.Telephone[0].ToString()  # use first entry
        } else {
          [DBNull]::Value
        }
      

      注意:如果$objUser.Telephone[0]直接返回[string],可以省略.ToString()调用。

      PowerShell v7+ 中,您也可以通过三元条件来缩短语句:

      $objDbCmd.Parameters["@telephone"].Value =
        $objUser.Telephone ? $objUser.Telephone[0].ToString() : [DBNull]::Value
      

      [1] 有关 PowerShell 自动到布尔转换的全面总结,请参阅this answer 的底部部分。

      [2] 当隐式将集合转换为字符串时,PowerShell默认以单个空格作为分隔符连接集合的字符串化元素;您可以使用自动$OFS 变量覆盖分隔符,但这在实践中很少这样做;例如,数组'foo', 'bar' 转换为'foo bar';请注意,当您调用集合的.ToString() 方法显式 时,此转换适用,但它确实适用于可扩展(插值)字符串,例如"$array"

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-11-26
        • 2011-10-02
        • 1970-01-01
        • 2013-07-26
        • 2014-02-20
        相关资源
        最近更新 更多