Подтвердить что ты не робот

Работа с System.DBNull в PowerShell

ОБНОВЛЕНИЕ: Начиная с PowerShell 7 Preview 2, -not [System.DBNull]::Value оценивается как $true, благодаря Джоелу Саллоу через запрос на выгрузку 9794

Тратить больше времени на извлечение данных SQL в PowerShell. Проблемы с [System.DBNull] :: Value и как PowerShell ведет себя с этим во время сравнений.

Вот пример поведения, которое я вижу, наряду с обходными путями

#DBNull values don't evaluate like Null...
    if([System.DBNull]::Value){"I would not expect this to display"}
    # The text displays.
    if([string][System.DBNull]::Value){"This won't display, but is not intuitive"}
    # The text does not display.

#DBNull does not let you use certain comparison operators
    10 -gt [System.DBNull]::Value 
    # Could not compare "10" to "". Error: "Cannot convert value "" to type "System.Int32". Error: "Object cannot be cast from DBNull to other types.""

    [System.DBNull]::Value -gt 10
    # Cannot compare "" because it is not IComparable.

    #No real workaround.  Must use test for null workaround in conjunction to avoid comparison altogether:
    [string][System.DBNull]::Value -and [System.DBNull]::Value -gt 10

#Example scenario with a function that uses Invoke-Sqlcmd2 to pull data
    Get-XXXXServer | Where-Object{$_.VCNumCPUs -gt 8}
    #Error for every line where VCNumCPU has DBNull value

    #workaround
    Get-XXXXServer | Where-Object{[string]$_.VCNumCPUs -and $_.VCNumCPUs -gt 8}

Я что-то упустил, или нет "простого" обходного пути, позволяющего людям с небольшим опытом использовать сравнения PowerShell, как и ожидалось?

Я отправил предложение по Connect, и у меня есть временный обходной путь от Дэйва Уайетта, который преобразует datarow в psobject-объекты, а dbnulls преобразуется в нули, но это добавляет немного накладных расходов, Похоже, что-то, что должно быть обработано под прикрытием, учитывая существующее "свободное" поведение PowerShell?

Какие-нибудь советы или я уже исчерпал свои возможности?

Спасибо!

4b9b3361

Ответ 1

Я думаю, вы здесь ошибаетесь. Поскольку документировано, класс DBNull представляет несуществующее значение, поэтому сравнения, такие как -gt или -lt, не имеют никакого смысла. Значение, которое не существует, не является ни большим, ни меньшим, чем любое заданное значение. Поле Value имеет метод Equals(), хотя и позволяет вам проверить, является ли это значение или нет DBNull:

PS C:> ([DBNull]::Value).Equals(23)
False
PS C:> ([DBNull]::Value).Equals([DBNull]::Value)
True

Ответ 2

Самый простой способ - это $var -isnot [DBNull].

Я проверил это в моих собственных сценариях, и это работает как ожидалось

Ответ 3

Что я обычно делаю, так это:

[String]::IsNullOrWhiteSpace($Val.ToString())

Или это:

[String]::IsNullOrEmpty($Val.ToString())

Или это:

$Val.ToString() -eq [String]::Empty

Это часто работает просто отлично, так как [System.DBNull]::Value.ToString() возвращает пустую строку, поэтому обе [String]::IsNullOrWhiteSpace([System.DBNull]::Value) и [System.DBNull]::Value.ToString() -eq [String]::Empty оцениваются как True.

Очевидно, что они не логически эквивалентны, поскольку ваши данные могут иметь законные пустые строки или могут быть типом данных, который не имеет смысла в виде пустой строки (например, целое число). Однако, поскольку вы часто хотите рассматривать DBNulls точно так же, как пустые строки и строки только для пробелов, это может быть полезно, если вы хорошо знаете свои данные.

Если вы действительно хотите узнать, является ли это значение DBNull, конечно, используйте [DBNull]::Value.Equals($Value).

Ответ 4

if( %youfunctetc%.GetType().Name -eq 'DBNull')
{}
else {}

Ответ 5

При работе с данными SQL в PS я включаю эту функцию и вызываю при необходимости:

function Check-IsNullWithSQLDBNullSupport ($var) {
    if ($var -eq [System.DBNull]::Value -or $var -eq $null) {
        return $true
    } else {
        return $false
    }
}

Может использоваться следующим образом:

if (Check-IsNullWithSQLDBNullSupport -var $VarToBeTested) {
    write-output "Is Null"
}

Ответ 6

некоторая команда | где FieldOfInterest -is DBNull Кажется, работает на меня. DBNull является типом, и оператор -is проверяет, имеет ли значение слева заданный тип.

Вы также можете использовать противоположное некоторая команда | где FieldOfInterest -is не DBNull