Extraño comportamiento en la función de PowerShell que devuelve DataSet / DataTable

Esto me está volviendo loca. Tengo una biblioteca que procedo de varias secuencias de comandos, que contiene la siguiente función:

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 } 

Esto se llama prácticamente en todas partes y funciona bien, excepto que normalmente tengo que hacer esto:

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

Así que creé una nueva función de envoltura simple para evitar el paso adicional de desreferenciar la primera tabla:

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

El problema es que lo que se devuelve aquí es la colección de filas de la tabla por algún motivo, no la tabla en sí. Esto hace que el bucle de fila foreach escrito como arriba falle con un “No se puede indexar en una matriz nula”. excepción. Después de mucho ensayo y error, descubrí que esto funciona:

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

Tenga en cuenta la diferencia entre $table.Rows y just $table en la statement foreach . Esto funciona Porque $table realmente apunta a la colección Filas. Si la statement

 return $ds.Tables[0] 

es supuestamente correcto, ¿por qué la función devuelve una colección secundaria del objeto de tabla en lugar de la tabla misma?

Supongo que hay algo en el funcionamiento de las funciones de Powershell que está causando esto obviamente, pero no puedo entender qué.

Puede usar el operador de coma para envolver la colección de filas en una matriz para que cuando se desenrolla la matriz finalice con la colección de filas original, por ejemplo:

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

Básicamente, no puede evitar que PowerShell desenrolle matrices / colecciones. Lo mejor que puedes hacer es solucionar ese comportamiento envolviendo la matriz / colección dentro de otra matriz de un solo elemento.

PowerShell special-cases el DataTable internamente. No implementa ninguna de las interfaces habituales sospechosas como ICollection, IList o IEnumerable que normalmente desencadenan el desenrollado. Puedes profundizar en esto un poco con:

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

Todavía:

 PS> $e = [management.automation.languageprimitives]::GetEnumerator($dt) PS> $e.gettype() IsPublic IsSerial Name BaseType -------- -------- ---- -------- False False RBTreeEnumerator System.ValueType 

-Oisin

Oh, sí, he estado luchando con esto también hasta que obtuve esta publicación … (¡txxs Keith!)

2 cosas que necesita para enfocarse en a) anteponer su objeto devuelto con la coma de hecho b) cuando está llenando su adaptador, asegúrese de asignar el resultado a una variable (descartable) o hacer un Out-Null

No hice Out-Null e incluso con una coma añadida, seguí obteniendo una colección de vuelta (elemento 0 = número de filas de la consulta, item1 = la tabla de datos) Me volví un poco loco hasta que elegí el Out-null parámetro fuera

Muy extraño en mi humilde opinión, ya que estoy pidiendo específicamente que devuelva la tabla de datos, pero siguió obteniendo la colección de nuevo, incluso con el “,” en frente

 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 } }