В .Net1.1 не очень удобно пакетно вставлять все данные из всего DataTable в базу данных или мигрировать между разными источниками данных. В .Net2.0 в пространство имен SQLClient было добавлено несколько новых классов, которые помогают нам переносить данные в пакетном режиме через DataTable или DataReader. Источником данных может быть реляционная база данных, XML-файл или даже результаты, возвращаемые WebService. Одним из наиболее важных классов является класс SqlBulkCopy, который может легко помочь нам перенести данные из источника данных в целевую базу данных.
Давайте сначала проиллюстрируем использование этого класса на простом примере:
ДатаВремя началаВремя;
protected void Button1_Click (отправитель объекта, EventArgs e)
{
startTime = ДатаВремя.Сейчас;
строка SrcConString;
строка DesConString;
SqlConnection SrcCon = новый SqlConnection();
SqlConnection DesCon = новый SqlConnection();
SqlCommand SrcCom = новый SqlCommand();
SqlDataAdapter SrcAdapter = новый SqlDataAdapter();
DataTable dt = новый DataTable();
СркКонСтрока =
ConfigurationManager.ConnectionStrings["SrcDBConnectionString"].ConnectionString;
ДесКонСтрока =
ConfigurationManager.ConnectionStrings["DesDBConnectionString"].ConnectionString;
SrcCon.ConnectionString = SrcConString;
Исходное соединение.Соединение = Исходное соединение;
SrcCom.CommandText = "ВЫБРАТЬ * Из [SrcTable]";
ИсходныйТипКоманды = ТипКоманды.Текст;
Источник.Соединение.Открыть();
SrcAdapter.SelectCommand = SrcCom;
SrcAdapter.Fill(дт);
SqlBulkCopy DesBulkOp;
DesBulkOp = новый SqlBulkCopy(DesConString,
SqlBulkCopyOptions.UseInternalTransaction);
DesBulkOp.BulkCopyTimeout = 500000000;
DesBulkOp.SqlRowsCopied +=
новый SqlRowsCopiedEventHandler (OnRowsCopied);
DesBulkOp.NotifyAfter = dt.Rows.Count;
пытаться
{
DesBulkOp.DestinationTableName = "SrcTable";
DesBulkOp.WriteToServer(дт);
}
поймать (Исключение ex)
{
lblResult.Text = ex.Message;
}
окончательно
{
Источник.Закрыть();
ДеКон.Закрыть();
}
}
Private void OnRowsCopied (отправитель объекта, SqlRowsCopiedEventArgs args)
{
lblCounter.Text += args.RowsCopied.ToString() + " строки копируются<Br>";
TimeSpan copyTime = DateTime.Now - startTime;
lblCounter.Text += "Время копирования:" + copyTime.Seconds.ToString() + "." + copyTime.Milliсекунды.ToString() + "секунды";
}
Затем подробно проанализируйте эти строки кода:
SqlBulkCopy DesBulkOp;
DesBulkOp = new SqlBulkCopy(DesConString, SqlBulkCopyOptions.UseInternalTransaction); Сначала создайте экземпляр SqlBulkCopy. Использование SqlBulkCopyOptions.UseInternalTransaction означает, что действие миграции указано в транзакции. Если во время миграции данных возникает ошибка или исключение. произойдет откат. Пожалуйста, обратитесь к MSDN для других вариантов.
DesBulkOp.BulkCopyTimeout = 500000000;
Укажите время ожидания завершения операции
DesBulkOp.SqlRowsCopied += new SqlRowsCopiedEventHandler(OnRowsCopied);
DesBulkOp.NotifyAfter = dt.Rows.Count;
пытаться
{
DesBulkOp.DestinationTableName = "SrcTable";
DesBulkOp.WriteToServer(дт);
}
Атрибут NotifyAfter указывает количество строк данных, которые должны быть обработаны перед событием уведомления. Здесь он указывается как количество строк в таблице, а событие SqlRowsCopied добавляется для вывода времени всего процесса миграции. Метод WriteToServer копирует источник данных в целевую базу данных. Перед использованием метода WriteToServer необходимо сначала указать атрибут DestinationTableName, который является именем таблицы целевой базы данных.
Мы также можем самостоятельно определить транзакцию, например:
SqlTransaction Transaction;
Транзакция =
SrcCom.Connection.BeginTransaction();
SqlBulkCopy DesBulkOp;
DesBulkOp = новый SqlBulkCopy (новый SqlConnection (DesConString),
SqlBulkCopyOptions.Default,
Транзакция);
попробуйте
{
//..
}
ловить{}
окончательно
{
Транзакция.Коммит();
}
Существует также класс SqlBulkCopyColumnMapping, который позволяет сопоставлять поля источника данных с полями с другими именами в целевых данных. То есть, если имена столбцов целевых данных и исходных данных различаются, вы можете использовать этот класс для сопоставления:
SqlBulkCopyColumnMapping ColMap = новый SqlBulkCopyColumnMapping("SrcCol", "DesCol");
DesBulkOp.ColumnMappings.Add(ColMap);
Или вы можете добавить сопоставление напрямую:
DesBulkOp.ColumnMappings.Add("SrcCol", "DesCol");
Проблемы с производительностью:
Я использовал приведенный выше пример для тестирования и переноса около 20 000 записей. На это ушло меньше секунды. Должен сказать, что производительность по-прежнему хорошая. Кроме того, используя SQL Profile для мониторинга событий миграции, вы можете видеть, что записей запросов очень мало, всего несколько. Говорят, что использование SqlBulkCopy позволяет значительно сократить время миграции данных.