PowerShell .NET过滤复杂列类型

时间:2016-04-04 14:53:39

标签: .net powershell datatable rowfilter

对于报告脚本,我在System.Data.DataTable中跟踪日志文件,其中一列也是System.Data.DataTable类型。此列基于某些不相关的代码填充,但它可能导致该列中的空数据表。我需要过滤该字段中具有空数据表的所有行。

查看DataView Rowfilter语法我无法弄清楚它是否可行,或者如何执行查询。如果我尝试遍历外部DataTable的Rows集合并检查嵌套的DataTable.Rows.Count属性,我会遇到修改外部数据表的问题,这会破坏枚举。

示例:

$somedt = New-Object System.Data.DataTable
[void]$somedt.Columns.add('foo')
[void]$somedt.Columns.Add('bar')
[void]$somedt.Rows.Add('boo', 'bah')
#$somedt

$dt = New-Object System.Data.DataTable
[void]$dt.Columns.Add('Title')
$dtcol = New-Object System.Data.DataColumn
$dtcol.DataType = [System.Data.DataTable]
$dtcol.DefaultValue = New-Object System.Data.DataTable
[void]$dt.Columns.Add($dtcol)
[void]$dt.Rows.Add("Orange")
[void]$dt.Rows.Add("Red")
[void]$dt.Rows.Add('Blue', $somedt)

$dt | Format-Table -AutoSize

给出了:

Title  Column1
-----  -------
Orange {}
Red    {}
Blue   {System.Data.DataRow}

理想情况下,我会按照以下方式做点什么:

$dt.Select("Title = 'Red'") | % { $_.Delete() }

但是过滤器应该在Column1.Rows.Count = 0上,我无法弄清楚如何(或者如果可能的话)。

这也不起作用:

foreach ($row in $dt.Rows) {
    if ($row.Column1.Rows.Count -eq 0) {
        $row.Delete()
     }
}

因为它在枚举期间尝试更改集合。如错误消息中所述:

Collection was modified; enumeration operation might not execute.
At line:22 char:10
+ foreach ($row in $dt.Rows) {
+          ~~~~
    + CategoryInfo          : OperationStopped: (:) [], InvalidOperationException
    + FullyQualifiedErrorId : System.InvalidOperationException


Title Column1
----- -------
Red   {}
Blue  {System.Data.DataRow}

并且不会删除“红色”行。在索引上尝试循环也是不成功的,因为索引也会在每次删除时都被更改。

我是否需要恢复为创建一个空的新数据表并相应地添加行?有点像这样:

$filtereddt = $dt.Clone()

foreach ($row in $dt) {
    if ($row.Column1.Rows.Count -gt 0) {
        $filtereddt.ImportRow($row)
    }
}

$filtereddt | Format-Table -AutoSize

正确显示:

Title Column1
----- -------
Blue  {System.Data.DataRow}

这正如预期的那样有效,但它只是觉得我忽略了一些东西,要么是一些高级RowFilter语法,要么是一些更优雅(?)的方式来过滤数据表。有什么建议吗?

更新

所以我正在尝试从注释中添加一个列,该列将跟踪Column1中DataTable对象的Rows.Count属性。我遇到的问题是,为了实现这一点,它必须是使用DataColumn.Expression自动计算的值。这似乎与Rowfilter语法有类似的限制,因为它似乎无法访问复杂数据类型的属性。

我想做点什么:

$rccol = New-Object System.Data.DataColumn
$rccol.ColumnName = "RowCount"
$rccol.Expression = "([Column1]).Rows.Count"

但这是不允许的。

所以现在我这样做:

foreach ($row in $dt.Rows) {
    $row.RowCount = $row.Column1.Rows.Count
}

所以我可以在不创建额外的“过滤数据表”的情况下进行过滤:

$dt.Select("RowCount = 0") | % { $_.Delete() }

我仍然想知道这是否是我脚本中最惯用/最好的解决方案,但我现在还会使用它。

0 个答案:

没有答案