Правильное использование таблиц данных

У меня есть процесс powershell, который запускается по запросу и собирает все журналы «История запросов» из приложения через вызовы веб-службы. Запросы результатов приводятся к объектам и имеют значения NoteProperty (пара атрибут-значение) в конечном итоге в большом массиве списка (обычно 1400 элементов) в неделю.

Что я хотел сделать, так это сохранить все эти запросы для исторических целей, чтобы приложение не удаляло их самостоятельно. Поэтому я создал простую таблицу в базе данных, в которой хранятся все пары значений атрибутов для каждого запроса, которых еще нет в моей только что созданной базе данных.

Затем я устанавливаю соединение OleDB в сценарии powershell с сервером MSSQL и выбираю все записи из таблицы, чтобы заполнить DataTable (я не очень хорошо разбираюсь в OleDB или DataTables). После этого я перебираю каждый элемент в массиве списка, чтобы убедиться, что он еще не существует в DataTable. Для каждой несуществующей записи я добавляю новую строку в DataTable с парами атрибут-значение. Отсюда я предполагаю, что построитель команд помогает с оператором Insert, поэтому мне не нужно проверять каждое значение атрибута, если оно пустое или пустое, или даже вообще писать запрос. Затем, наконец, я «обновляю» OleDBAdapter с помощью недавно добавленной DataTable.

Хотя этот процесс работает, я понял, что он извлекает все данные из базы данных, затем сравнивает их с моим массивом списка и повторно фиксирует вновь добавленные записи. Чем больше база данных, тем больше времени это занимает. Есть ли способ сделать это быстрее и эффективнее без написания каких-либо операторов SQL? Мне нравится, как CommandBuilder работает с таблицами данных.

Ниже приведена функция, вызываемая для обновления базы данных после получения всех объектов «История запросов».

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

person The Unique Paul Smith    schedule 25.04.2012    source источник


Ответы (1)


Вам нужно будет написать небольшой код T-SQL, чтобы сделать процесс более эффективным. Вам нужно будет отправить новые строки на SQL Server, чтобы обработка происходила на SQL Server. Одним из решений является использование табличных параметров, которые позволяют передавать DataTable в SQL Server. У меня есть блог пример здесь:

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

person Chad Miller    schedule 27.04.2012
comment
Спасибо @chad, я рассмотрю возможность использования табличных параметров, хотя я не уверен, есть ли у меня доступ для создания процедур хранения. - person The Unique Paul Smith; 01.05.2012