【问题标题】:Can Powershell Receive-Job return a DataSet?Powershell Receive-Job 可以返回数据集吗?
【发布时间】:2014-03-02 02:35:57
【问题描述】:

背景信息

我有一个应用程序,它与多个数据库建立多个 SQL 连接,目前需要很长时间才能执行。

Powershell (.NET) 将等待每个正在进行的“SQL-GET”函数完成,然后才能触发下一个。我的印象是我可以通过同时在他们自己的后台作业中触发每个“SQL-GET”函数来显着加快这个应用程序的速度!然后,我会在他们完成时从每个作业中检索数据。理想情况下作为 DataSet 系统对象。

问题

从后台作业中检索数据时,我只能设法取回一个 System.Array 对象。我真正追求的是一个 System.DataSet 对象。这是必要的,因为应用程序中的所有逻辑都依赖于 DataSet 对象。

守则

这是一段非常简单的代码,它将创建一个 sql 连接并用返回的结果填充一个新创建的数据集对象。工作一种享受。 $results 是一个 DataSet 对象,我可以很好地操作它。

$query = "SELECT * FROM [database]..[table] WHERE column = '123456'"

$Connection = New-Object System.Data.SqlClient.SQLConnection      
$ConnectionString = "Server='SERVER';Database='DATABASE';User ID='SQL_USER';Password='SQL_PASSWORD'"  
$Connection.ConnectionString = $ConnectionString     
$Connection.Open() 
$Command = New-Object system.Data.SqlClient.SqlCommand($Query,$Connection) 
$Adapter = New-Object system.Data.SqlClient.SqlDataAdapter
$Adapter.SelectCommand = $Command
$Connection.Close() 
[System.Data.SqlClient.SqlConnection]::ClearAllPools()

$results = New-Object system.Data.DataSet 

[void]$Adapter.fill($results)

$results.Tables[0]

这是包装在新后台作业的 scriptblock 参数中的非常相同的代码。只有在调用 Receive-Job 时,我才得到一个数组,而不是数据集。

     $test_job = Start-Job -ScriptBlock {

$query = "SELECT * FROM [database]..[table] WHERE column = '123456'"

$Connection = New-Object System.Data.SqlClient.SQLConnection      
$ConnectionString = "Server='SERVER';Database='DATABASE';User ID='SQL_USER';Password='SQL_PASSWORD'"  
$Connection.ConnectionString = $ConnectionString     
$Connection.Open() 
$Command = New-Object system.Data.SqlClient.SqlCommand($Query,$Connection) 
$Adapter = New-Object system.Data.SqlClient.SqlDataAdapter
$Adapter.SelectCommand = $Command
$Connection.Close() 
[System.Data.SqlClient.SqlConnection]::ClearAllPools()

$results = New-Object system.Data.DataSet 

[void]$Adapter.fill($results) 
return $results.Tables[0]

}

Wait-Job $test_job
$ret_results = Receive-Job $test_job

任何帮助将不胜感激!!!

迄今为止的研究

我使用的是旧版 Google,但我偶然发现的所有帖子、博客和文章似乎都非常深入地探讨了工作管理以及与此相关的所有花里胡哨。仅通过receive-job cmdlet返回一个数组是powershell的底层特性吗?

我已经阅读了关于返回表达式的stack post。以为我在做某事。尝试:

  • return $results.Tables[0]
  • return ,$results.Tables[0]
  • return ,$results

仍然返回一个数组。

我见过人们,相当麻烦,手动将数组转换回数据集对象 - 虽然这看起来很“肮脏” - 我很迂腐,希望这个神奇的数据集对象必须有一种方法可以遍历后台工作并进入我当前的会话! :)

重申

基本上,我只想让从 Receive-Job cmdlet 中检索到的 $ret_results 对象成为一个 DataSet……甚至是一个 DataTable。我会采取任何一个......只是不是一个阵列:)

【问题讨论】:

    标签: .net powershell powershell-3.0 powergui powershell-jobs


    【解决方案1】:

    在 powershell 中,一组多个任意类型的对象在集合中返回是很常见的。考虑这个我构建自己的表的更改示例:

    PS C:\> $job = Start-Job -ScriptBlock {
    >>
    >> $table = New-Object system.Data.DataTable “MyTable”
    >>
    >> $col1 = New-Object system.Data.DataColumn MyFirstCol,([string])
    >> $col2 = New-Object system.Data.DataColumn MyIntCol,([int])
    >>
    >> $table.columns.add($col1)
    >> $table.columns.add($col2)
    >>
    >> $row1 = $table.NewRow()
    >> $row1.MyFirstCol = "FirstRow"
    >> $row1.MyIntCol = 1
    >> $row2 = $table.NewRow()
    >> $row2.MyFirstCol = "SecondRow"
    >> $row2.MyIntCol = 2
    >>
    >> $table.Rows.Add($row1)
    >> $table.Rows.Add($row2)
    >>
    >> $dataSet = New-Object system.Data.DataSet
    >> $dataSet.Tables.Add($table)
    >>
    >> $dataSet.Tables[0]
    >>
    >> }
    >>
    PS C:\> $output = Receive-Job -Job $job
    

    已收到输出。那么我们得到了什么?

    PS C:\> $output.GetType()
    
    IsPublic IsSerial Name                                     BaseType
    -------- -------- ----                                     --------
    True     True     Object[]                                 System.Array
    

    一个数组,正如你所描述的。但这就是整个对象。如果我们通过管道将其成员单独分析到Get-Member 会怎样?

    PS C:\> $output | gm
    
       TypeName: Deserialized.System.Data.DataRow
    
    Name               MemberType   Definition
    ----               ----------   ----------
    ToString           Method       string ToString(), string ToString(string format, System.IFormatProvider formatProvi...
    PSComputerName     NoteProperty System.String PSComputerName=localhost
    PSShowComputerName NoteProperty System.Boolean PSShowComputerName=False
    RunspaceId         NoteProperty System.Guid RunspaceId=186c51c3-d3a5-404c-9a4a-8ff3d3a7f024
    MyFirstCol         Property     System.String {get;set;}
    MyIntCol           Property     System.Int32 {get;set;}
    
    PS C:\> $output
    
    
    RunspaceId : 186c51c3-d3a5-404c-9a4a-8ff3d3a7f024
    MyFirstCol : FirstRow
    MyIntCol   : 1
    
    RunspaceId : 186c51c3-d3a5-404c-9a4a-8ff3d3a7f024
    MyFirstCol : SecondRow
    MyIntCol   : 2
    

    考虑以下几点:

    • 在您的工作中,您已指定应返回 $results.Tables[0]。通过指定特定的 Tables 迭代,您将返回描述该表的对象...可能是 DataTable,或者在本例中为 DataRows...而不是您似乎期望的 DataSet?

    • 数据表有行。如果 DataTable 有不止一行,powershell 会将它返回到 DataRows 的集合中,正如我在上面演示的那样。您可能会惊讶地发现,单行返回并非如此——它只会返回单个 DataRow 对象,而不是 DataRow 对象的集合。

    • 如果这确实是您所期望的输出,您可能希望通过将输出指定为 @($results.Tables[0]) 来强制它始终在集合中返回。这样一来,您始终知道需要一个集合,并且可以适当地处理结果内容(通过遍历集合来管理各个对象)。

    【讨论】:

    • @Hhyper-anthony,感谢您的快速回复!首先,我刚刚意识到 DataSet 对象用于存储 DataTable 对象的集合,因此我可以在上面的代码示例中安全地用 D​​ataTable 替换 DataSet。经过进一步检查,您是绝对正确的,因为返回的数据实际上是 System.Data.DataRow 对象的数组。这可以很容易地干净地构造回 DataTable。
    【解决方案2】:

    当您将脚本作为 PS 作业运行时,您正在创建一个新进程 (pid),并且无法真正从父作业中获取相同的对象。您使用 Receive-Job cmdlet 收到的是该对象的反序列化副本(所有属性都将转换为基本类型(如字符串/数字/等)并且方法将被删除。

    但有一个解决方案 - 运行空间。运行空间是在与单独线程相同的 pid 中创建的子进程。几乎是异步函数(脚本块)执行。检查以下示例:

    $script =  {
        $dt = new-object System.Data.DataTable
        $dt.Columns.add() | Out-Null
        $dt.Columns.add() | Out-Null
        $dt.Rows.Add(1,2) | Out-Null
        $dt.Rows.Add(3,4) | Out-Null
        $ds = New-Object System.Data.DataSet
        $ds.Tables.Add($dt)
        Write-Output @{ds = $ds}
    }
    
    $PowerShell = [powershell]::Create()
    $Runspace = [runspacefactory]::CreateRunspace()
    $PowerShell.runspace = $Runspace
    $Runspace.Open()
    
    [void]$PowerShell.AddScript($script)
    $result = $PowerShell.Invoke()
    $result.ds.gettype()
    

    此代码在运行空间内执行 $script 脚本块。此示例没有异步运行它(需要使用 BeginInvoke/EndInvoke,为简单起见跳过了它),但正如您所见,它返回的是实际的 DataSet/DataTable,而不是 PSObject

    要了解更多信息,请查看 Scripting Guy 的这些帖子: https://blogs.technet.microsoft.com/heyscriptingguy/2015/11/26/beginning-use-of-powershell-runspaces-part-1/ 他还创建了一个 PoshRSJob 模块 - 它反映了标准作业 cmdlet,但使用了运行空间(异步执行)

    【讨论】:

      猜你喜欢
      • 2012-08-12
      • 2020-03-29
      • 1970-01-01
      • 2020-07-25
      • 2015-07-06
      • 1970-01-01
      • 2011-11-17
      • 1970-01-01
      相关资源
      最近更新 更多