1

我有一个按需运行的 powershell 进程,它通过 Web 服务调用从应用程序收集所有“请求历史记录”日志。结果请求被强制转换为对象,并且 NoteProperty 值(属性-值对)每周以一个大列表数组(通常 1400 个项目)结束。

我想要做的是存储所有这些请求以用于历史目的,这样应用程序就不会自行清除它们。因此,我在数据库上创建了一个简单的表,该表存储了我新创建的数据库中尚不存在的每个请求的所有属性值对。

然后,我在 powershell 脚本中设置了与 MSSQL 服务器的 OleDB 连接,并从表中选择所有记录来填充 DataTable(我不擅长使用 OleDB 或 DataTables)。之后,我循环遍历列表数组中的每个项目以验证它在 DataTable 中不存在。对于每条不存在的记录,我在 DataTable 中添加一个带有属性值对的新行。从那里我假设命令生成器有助于插入语句,因此我不必检查每个属性值是否为空或空白,甚至根本不需要编写查询。最后,我用新添加的 DataTable“更新”了 OleDBAdapter。

虽然这个过程有效,但我意识到它正在做的是从数据库中提取所有数据,然后与我的列表数组进行比较并重新提交新添加的记录。数据库越大,所需的时间就越长。无论如何,无需编写任何 SQL 语句就可以快速、更有效地做到这一点吗?我喜欢 CommandBuilder 如何为 DataTables 工作。

以下是获取所有“请求历史记录”对象后调用以更新数据库的函数

function UpdateDatabase([Parameter(Mandatory=$true)] $allRequests)
{
    $objOleDbConnection = New-Object "System.Data.OleDb.OleDbConnection"
    $objOleDbCommand = New-Object "System.Data.OleDb.OleDbCommand"
    $objOleDbAdapter = New-Object "System.Data.OleDb.OleDbDataAdapter"
    $objDataTable = New-Object "System.Data.DataTable"

    $objOleDbConnection.ConnectionString = "Provider=SQLNCLI10;Server=SERVER;Database=DB1;Trusted_Connection=yes;"
    $objOleDbConnection.Open()

    $objOleDbCommand.Connection = $objOleDbConnection
    $objOleDbCommand.CommandText = "SELECT * FROM dbo.RequestLog"

    ##set the Adapter object and command builder
    $objOleDbAdapter.SelectCommand = $objOleDbCommand
    $objOleDbCommandBuilder = New-Object "System.Data.OleDb.OleDbCommandBuilder"
    $objOleDbCommandBuilder.DataAdapter = $objOleDbAdapter

    ##fill the objDataTable object with the results
    [void] $objOleDbAdapter.Fill($objDataTable)
    [void] $objOleDbAdapter.FillSchema($objDataTable,[System.Data.SchemaType]::Source)

    #store all the primary keys in a list for kicking out dups
    $sql_id = @()
    $objDataTable.Rows | foreach { $sql_id += $_.PKID}

    #####

    #loop through all the requests
    trap {
    "Error: $($i)"
    }
    $i = 0
    $total = $allRequests.count
    foreach ($request in $allRequests)
    {       
        $i++
        write-progress -activity "Filling DataTable" -status "% Complete: $($i/$total*100)" -PercentComplete ($i/$total*100)
        #check to see if entry already exists in our table (by primary key)
        if (!($sql_id -contains $request.PKID.Value))
        {
            #shouldn't have to do this but i noticed sometimes requests are duplicate in the list? (probably restarted the script and caught some old requests
            $sql_id += $request.PKID.Value

            $row = $objDataTable.Rows.Add($request.PKID.Value)
            #go through all the attributes from the request and add them to the table
            $list = get-member -in $request | Where-Object { $_.MemberType -eq "NoteProperty" }
            foreach ($attr in $list)
            {
                if ($request.($attr.name) -ne $null)
                {
                    $row.($attr.name) = $request.($attr.name)
                }
            }

        } else { 
            #PKID already in DB
        }

    }
    #update the database with our new records
    $objOleDbAdapter.Update($objDataTable)

    ## close the connection 
    $objOleDbConnection.Close()
}
4

1 回答 1

1

您将需要编写一些 T-SQL 代码来提高该过程的效率。您需要将新行发送到 SQL Server,以便在 SQL Server 上进行处理。一种解决方案是使用表值参数,它允许您将 DataTable 传递给 SQL Server。我在这里写了一个例子:

http://sev17.com/2012/04/appending-new-rows-only/

于 2012-04-27T16:13:50.837 回答