[Delphi] Afinal, qual é a melhor forma de copiar registros de um DataSet?

Saudações, leitores!
O artigo de hoje traz uma dúvida relativamente comum. Eventualmente, por conta das regras de negócio do cliente ou uma migração de dados, surge a necessidade de copiar vários registros de um DataSet para outro. Neste momento, uma das nossas maiores preocupações é a performance dessa operação, concordam? Confira, neste artigo, algumas formas de realizar essa cópia e a apresentação de dois ótimos recursos que o FireDAC nos oferece para essa finalidade.

Introdução

Algumas vezes recebo e-mails com a seguinte dúvida:

André, preciso copiar vários registros entre dois DataSets. Qual a melhor forma? Executar um loop e copiar cada campo através do FieldByName?

O motivo que causa essa dúvida, a princípio, está relacionado ao requisito de desempenho da rotina. Os programadores buscam a melhor forma de codificação para reduzir, ao máximo, o tempo dispendido pela operação, afinal, quando nos referimos a estruturas de repetição, devemos ter cautela nas instruções dentro da iteração para não comprometer a experiência do usuário.

Por conta disso, como forma de contribuição para a comunidade Delphi, fiz questão de abordar este assunto no blog.
Para que o artigo fique em uma estrutura didática, cada solução foi dividida em diferentes seções, ordenadas por recomendação em ordem crescente. Vamos lá!

1) Executar um loop no DataSet, copiando os valores com FieldByName

A primeira forma é utilizar um loop para percorrer os registros do DataSet, copiando os valores de cada campo através do método FieldByName:

Há alguns anos, foram publicados alguns artigos na internet com orientações para evitar o uso do FieldByName, já que, até então, este método realizava um loop em uma lista de objetos do DataSet para encontrar o campo desejado. Porém, desde o Delphi Seattle, a lista que armazena os Fields do DataSet foi substituída pelo TDictionary, que possui uma performance evidentemente melhor. Apenas a título de conhecimento, essa alteração pode ser encontrada na classe TFields:

Portanto, não se preocupe mais com desempenho ao utilizar o FieldByName. 🙂

2) Executar um loop no DataSet, copiando os valores com variáveis TField

Mesmo assim, se você prefere evitar o uso do FieldByName, existe a opção de criar variáveis do tipo TField e apontá-las para os campos do DataSet antes de iniciar as iterações:

O mesmo pode ser feito para os campos de origem, mas, neste caso, teríamos o dobro de variáveis do tipo TField.

3) Executar um loop nos Fields para evitar a repetição de código

A terceira opção é usar um loop dentro de um loop. O primeiro itera os registros e o segundo itera os Fields do DataSet com uma instrução For-In. Dessa forma, evitamos a necessidade de escrever uma linha para cada campo, tornando-se um benefício quando os DataSets possuem dezenas de campos a serem copiados:

Vale ressaltar que essa opção só é viável quando os dois DataSets possuem a mesma estrutura de Fields, inclusive na mesma ordem. Caso contrário, os valores de alguns campos no DataSet de destino poderão ficar inconsistentes, já que foram copiados de campos diferentes.

4) FireDAC: usando o método CopyRecord

Além da enorme quantidade de vantagens proporcionadas, a tecnologia FireDAC também trouxe o método CopyRecord, disponível para copiar todos os valores do registro atual de um DataSet. Acompanhe:

Não precisamos utilizar o FieldByName ou variáveis TField, sem contar que, claro, o código fica bem mais limpo. Além disso, o próprio método se encarrega de copiar apenas os campos correspondentes, caso a estrutura dos DataSets não seja equivalente.

5) FireDAC: o poderoso método CopyDataSet

Se eu disser que podemos executar essa cópia com apenas uma instrução, vocês acreditariam? Pois bem, o método CopyDataSet copia todos os valores de todos os registros de um DataSet, respeitando a mesma característica de campos correspondentes:

Um grande diferencial deste método é a performance. Em um teste rápido, usando um DataSet com 4 campos e 5.000 registros, o loop com CopyRecord levou 6.58 segundos, enquanto o CopyDataSet demorou 0.04.

Menos de 1 segundo?!
Exato, meu amigo! Migre já para o FireDAC! 🙂

Fico por aqui, pessoal.
Qualquer dúvida, observação ou contribuição, não hesite em deixar um comentário.
Abraço!


André Celestino