Странное поведение в функции PowerShell, возвращающей DataSet / DataTable - PullRequest
20 голосов
/ 17 декабря 2009

Это сводит меня с ума. У меня есть библиотека из нескольких сценариев, в которой содержится следующая функция:

function lib_open_dataset([string] $sql) {
    $ds = new-object "System.Data.DataSet"
    $da = new-object "System.Data.SqlClient.SqlDataAdapter" ($sql, $_conn_string)

    $record_count = $da.Fill($ds)

    return $ds
}

Это называется почти везде, и работает нормально, за исключением того, что я обычно должен это делать:

$ds = lib_open_dataset($some_sql)
$table = $ds.Tables[0]
foreach ($row in $table.Rows) {
    # etc
}

Итак, я создал новую простую функцию-обертку, чтобы избежать дополнительного шага разыменования первой таблицы:

function lib_open_table([string] $sql) {
    $ds = lib_open_dataset $sql
    return $ds.Tables[0]
}

Проблема в том, что отсюда возвращается набор строк таблицы по какой-то причине, а не сама таблица 1013 *. Это приводит к сбою цикла строки foreach, написанного, как указано выше, с «Cannot index to null array». исключение. После долгих проб и ошибок я понял, что это работает:

foreach ($row in $table) {
    # etc
}

Обратите внимание на разницу между $table.Rows и $table в выражении foreach. Это работает . Потому что $table фактически указывает на коллекцию строк. Если заявление

return $ds.Tables[0]

предположительно правильно, почему функция возвращает дочернюю коллекцию объекта таблицы вместо самой таблицы?

Полагаю, что в функциях Powershell есть что-то, вызывающее это, но я не могу понять, что именно.

Ответы [ 3 ]

23 голосов
/ 17 декабря 2009

Вы можете использовать оператор запятой, чтобы обернуть коллекцию строк в массив так, чтобы при развертывании массива вы получали исходную коллекцию строк, например ::100100

function lib_open_table([string] $sql) {
    $ds = lib_open_dataset $sql    
    return ,$ds.Tables[0]
}

По сути, вы не можете запретить PowerShell развертывать массивы / коллекции. Лучшее, что вы можете сделать, - это обойти это поведение, поместив массив / коллекцию в другой массив из одного элемента.

12 голосов
/ 19 декабря 2009

Особые случаи PowerShell для DataTable внутри. Он не реализует какие-либо обычные подозрительные интерфейсы, такие как ICollection, IList или IEnumerable, которые обычно запускают развертывание. Вы можете немного покопаться в этом:

PS> $dt = new-object data.datatable
PS> $dt -is [collections.ienumerable]
False

Тем не менее:

PS> $e = [management.automation.languageprimitives]::GetEnumerator($dt)
PS> $e.gettype()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
False    False    RBTreeEnumerator                         System.ValueType

-Oisin

4 голосов
/ 19 мая 2011

О да, я тоже боролся с этим, пока не получил этот пост .. (tnxs Кит!)

2 вещи, на которых вы действительно должны сосредоточиться а) добавьте к возвращенному объекту запятую б) когда вы заполняете свой адаптер, убедитесь, что вы либо присвоили результат (утилизируемой) переменной , либо выполните Out-Null

Я не делал Out-Null и даже с добавленной запятой я продолжал возвращать коллекцию (item 0 = количество строк в запросе, item1 = datatable) Немного сводил меня с ума, пока я не выбрал параметр Out-null.

Очень странно, ИМХО, поскольку я специально просил вернуть данные, но продолжал возвращать коллекцию, даже с "," перед

function  Oracleconnection
{
  process
  {
  trap
    {
      Write-Host "error occured on oracle connection"
      Write-Host $_
      continue
    }
    [System.Reflection.Assembly]::LoadWithPartialName(“System.Data.OracleClient”) | out-null
    $connection = new-object system.data.oracleclient.oracleconnection( `
    "Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=myhost.host)(PORT=1800)) `
    (CONNECT_DATA=(SERVICE_NAME=myservicename)));User Id=myid;Password=mypassword;");

    $query = "SELECT country, asset FROM table "
    $set = new-object system.data.dataset
    $adapter = new-object system.data.oracleclient.oracledataadapter ($query, $connection)
    $adapter.Fill($set) | Out-Null
    $table = new-object system.data.datatable
    $table = $set.Tables[0]
    return ,$table
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...