No .Net1.1, não é muito conveniente inserir em lote todos os dados de todo o DataTable no banco de dados ou migrar entre diferentes fontes de dados. No .Net2.0, várias novas classes foram adicionadas ao namespace SQLClient para nos ajudar a migrar dados em lotes por meio de DataTable ou DataReader. A fonte de dados pode ser proveniente de um banco de dados relacional ou arquivo XML, ou ainda dos resultados retornados pelo WebService. Uma das classes mais importantes é a classe SqlBulkCopy, que pode facilmente nos ajudar a migrar dados da fonte de dados para o banco de dados de destino.
Vamos primeiro ilustrar o uso desta classe através de um exemplo simples:
DataHora startTime;
protegido vazio Button1_Click (objeto remetente, EventArgs e)
{
startTime = DateTime.Agora;
stringSrcConString;
string DesConString;
SqlConnection SrcCon = new SqlConnection();
SqlConnection DesCon = new SqlConnection();
SqlCommand SrcCom = new SqlCommand();
SqlDataAdapter SrcAdapter = new SqlDataAdapter();
DataTable dt = new DataTable();
StringConString =
ConfigurationManager.ConnectionStrings["SrcDBConnectionString"].ConnectionString;
DesConString =
ConfigurationManager.ConnectionStrings["DesDBConnectionString"].ConnectionString;
SrcCon.ConnectionString = SrcConString;
SrcCom.Connection = SrcCon;
SrcCom.CommandText = "SELECIONE * De [SrcTable]";
SrcCom.CommandType = CommandType.Text;
SrcCom.Connection.Open();
SrcAdapter.SelectCommand = SrcCom;
SrcAdapter.Fill(dt);
SqlBulkCopy DesBulkOp;
DesBulkOp = new SqlBulkCopy(DesConString,
SqlBulkCopyOptions.UseInternalTransaction);
DesBulkOp.BulkCopyTimeout = 500000000;
DesBulkOp.SqlRowsCopied +=
novo SqlRowsCopiedEventHandler(OnRowsCopied);
DesBulkOp.NotifyAfter = dt.Rows.Count;
tentar
{
DesBulkOp.DestinationTableName = "SrcTable";
DesBulkOp.WriteToServer(dt);
}
pegar (exceção ex)
{
lblResult.Text = ex.Mensagem;
}
finalmente
{
SrcCon.Close();
DesCon.Close();
}
}
private void OnRowsCopied (remetente do objeto, argumentos SqlRowsCopiedEventArgs)
{
lblCounter.Text += args.RowsCopied.ToString() + "linhas são copiadas<Br>";
TimeSpan copyTime = DateTime.Now - startTime;
lblCounter.Text += "Tempo de cópia:" + copyTime.Seconds.ToString() + "." + copyTime.Milliseconds.ToString() + " segundos";
}
Em seguida, analise essas linhas de código em detalhes:
SqlBulkCopy DesBulkOp;
DesBulkOp = new SqlBulkCopy(DesConString, SqlBulkCopyOptions.UseInternalTransaction); Primeiro gere uma instância SqlBulkCopy. Se ocorrer um erro ou exceção durante a migração de dados, ocorrerá uma reversão. Consulte o MSDN para outras opções.
DesBulkOp.BulkCopyTimeout = 500000000;
Especifique o tempo limite para a conclusão da operação
DesBulkOp.SqlRowsCopied += new SqlRowsCopiedEventHandler(OnRowsCopied);
DesBulkOp.NotifyAfter = dt.Rows.Count;
tentar
{
DesBulkOp.DestinationTableName = "SrcTable";
DesBulkOp.WriteToServer(dt);
}
O atributo NotifyAfter especifica o número de linhas de dados a serem processadas antes do evento de notificação. Aqui, ele é especificado como o número de linhas na tabela e o evento SqlRowsCopied é adicionado para gerar a hora de todo o processo de migração. O método WriteToServer copia a fonte de dados para o banco de dados de destino. Antes de usar o método WriteToServer, você deve primeiro especificar o atributo DestinationTableName, que é o nome da tabela do banco de dados de destino.
Também podemos definir uma Transaction, por exemplo:
SqlTransaction Transaction;
Transação =
SrcCom.Connection.BeginTransaction();
SqlBulkCopy DesBulkOp;
DesBulkOp = novo SqlBulkCopy(novo SqlConnection(DesConString),
SqlBulkCopyOptions.Default,
Transação);
tente
{
//..
}
pegar{}
finalmente
{
Transação.Commit();
}
Há também uma classe SqlBulkCopyColumnMapping que permite que campos de origem de dados sejam mapeados para campos com nomes diferentes nos dados de destino. Ou seja, se os nomes das colunas dos dados de destino e dos dados de origem forem diferentes, você poderá usar esta classe para mapeamento:
SqlBulkCopyColumnMapping ColMap = new SqlBulkCopyColumnMapping("SrcCol", "DesCol");
DesBulkOp.ColumnMappings.Add(ColMap);
Ou você pode adicionar mapeamento diretamente:
DesBulkOp.ColumnMappings.Add("SrcCol", "DesCol");
Problemas de desempenho:
Usei o exemplo acima para testar e migrei cerca de 20.000 registros. Demorou menos de um segundo. Devo dizer que o desempenho ainda é bom. Além disso, usando o SQL Profile para monitorar eventos de migração, você pode ver que há poucos registros de solicitação, apenas alguns. Diz-se que o uso do SqlBulkCopy pode reduzir bastante o tempo de migração de dados.