Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/powershell/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net Powershell能否接收作业并返回数据集?_.net_Powershell_Powershell 3.0_Powergui_Powershell Jobs - Fatal编程技术网

.net Powershell能否接收作业并返回数据集?

.net Powershell能否接收作业并返回数据集?,.net,powershell,powershell-3.0,powergui,powershell-jobs,.net,Powershell,Powershell 3.0,Powergui,Powershell Jobs,背景信息: 我有一个应用程序,它可以与多个数据库建立多个SQL连接,目前执行这些连接需要很长时间 Powershell(.NET)将等待每个正在进行的“SQL-GET”函数完成,然后才能启动下一个。我的印象是,通过在自己的后台工作中同时启动每个“SQL-GET”函数,我可以大大加快这个应用程序的速度!然后,我将在每个作业完成时从中检索数据。理想情况下作为数据集系统对象 问题: 从后台作业检索数据时,我只能设法取回一个System.Array对象。我实际上想要的是一个System.DataSet对

背景信息

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

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

问题

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

代码

下面是一段v.simple代码,它将创建一个sql连接,并用返回的结果填充一个新创建的dataset对象。工作是一种享受。$results是一个数据集对象,我可以很好地处理它

$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
任何帮助都将不胜感激

迄今为止的研究

我用的是老谷歌,但我偶然发现的所有帖子、博客和文章似乎都非常深入地探讨了如何管理工作以及与此相关的所有问题。powershell的基本特性是仅通过receive job cmdlet返回数组吗

我读了一篇关于返回表达式的文章。我以为我知道了什么。尝试:

  • 返回$results.表[0]
  • 返回$results.Tables[0]
  • 返回$results
仍然返回一个数组

我见过一些人,相当麻烦地,手动将数组转换回数据集对象-尽管这看起来很“脏”-我很迂腐,并希望一定有办法让这个神奇的数据集对象穿越后台工作并进入我当前的会话

重申


基本上,我只想让从Receive Job cmdlet检索到的$ret_results对象成为DataSet…甚至是DataTable。我会选择其中一个…只是不是数组:)

在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]
    。通过指定特定的表迭代,您将返回描述该表的对象。。。可能是DataTable,或者在本例中是DataRows。。。而不是像你期望的那样的数据集

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

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


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

但是有一个解决方案-运行空间。运行空间是在同一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 scriptblock。此示例没有异步运行它(需要使用BeginInvoke/EndInvoke,只是为了简单起见跳过了它),但正如您所看到的,它返回的是实际的DataSet/DataTable,而不是PSObject

要了解更多信息,请查看以下来自Scripting Guy的帖子:
他还创建了一个PoshRSJob模块——它镜像了标准作业cmdlet,但使用了运行空间(异步执行)

@Hhyper anthony,感谢您的快速回复!首先,我刚刚意识到DataSet对象用于存储DataTable对象的集合,因此我可以在上面的代码示例中安全地用DataTable替换DataSet。进一步检查后,您完全正确,返回的数据实际上是System.data数组。DataRow对象。这可以轻松地构造回数据表。