Maneira simples de copiar ou clonar um DataRow?

118

Estou procurando uma maneira simples de fazer um clone de um DataRow. É como tirar um instantâneo daquele Row e salvá-lo. Os valores da linha original podem então ser alterados, mas ainda temos outra cópia salva que não muda. Esta é a maneira correta de fazer isso?

DataRow Source, Destination;
// Assume we create some columns and fill them with values
Destination.ItemArray = Source.ItemArray;

Isso apenas definirá a referência do ItemArray do Snapshot para apontar para aquele em Source ou realmente fará uma cópia separada? Devo fazer isso em vez disso?

Destination.ItemArray = Source.ItemArray.Clone();

EDIT: Eu não acho que o segundo trecho de código realmente compila.

Paul Matthews
fonte
Não tenho certeza se entendi. Você deseja copiar um datarow de uma tabela para outra? Se for assim, acredito que usar DataTable.ImportRow é o que você procura.
Mo Patel de
Ok, vejo que minha pergunta precisa ser reformulada agora
Paul Matthews
2
Observe que, em alguns cenários, você pode não precisar fazer isso porque o próprio datarow oferece suporte à edição transacional com BeginEdit / EndEdit / CancelEdit; também você pode chamar .RejectChanges nele.
peterG

Respostas:

185

Você pode usar o ImportRowmétodo para copiar Row de DataTable para DataTable com o mesmo esquema:

var row = SourceTable.Rows[RowNum];
DestinationTable.ImportRow(row);

Atualizar:

Com sua nova edição, eu acredito:

var desRow = dataTable.NewRow();
var sourceRow = dataTable.Rows[rowNum];
desRow.ItemArray = sourceRow.ItemArray.Clone() as object[];

vai funcionar

cuongle
fonte
Aparentemente, Clone () fornece apenas uma cópia superficial. Você acha que isso será suficiente para criar uma cópia idêntica ou é necessário um clone profundo?
Paul Matthews
5
@PaulMatthews: Felizmente, DataTable contém tipos de valor, não tipo ref, portanto, a cópia superficial no tipo de valor é o mesmo que a cópia profunda
cuongle
16
Para as pessoas que encontrarem esta postagem, acrescentarei o seguinte, como já me perguntaram com frequência, então acho que outras pessoas podem estar confusas. Clone copie apenas a estrutura, Copie copie a estrutura e depois os dados. Isso está sendo dito, outra maneira fácil de copiar dados, uma vez que ambas as tabelas instanciadas, é criar uma nova linha na tabela de destino e usar o seguinte: destRow.ItemArray = sourceRow.ItemArrayentão, basta adicionar a linha de volta comdestTable.Rows.Add(destRow);
Franck
1
Estou tentando usar esse método para obter um clone de um datarow. Eu sigo as etapas a seguir, apago a tabela de dados que contém a linha de origem e agora tenho uma linha de origem com campos em branco.
Sergеу Isupov,
Descobri que usar o método ImportRow funcionou para mim, enquanto o método NewRow não funcionou.
OldDog
2

Observação: a resposta helfpul de cuongle tem todos os ingredientes, mas a solução pode ser simplificada (não há necessidade .ItemArray) e pode ser reformulada para corresponder melhor à pergunta feita.

Para criar um clone (isolado) de uma determinada System.Data.DataRowinstância , você pode fazer o seguinte:

// Assume that variable `table` contains the source data table.

// Create an auxiliary, empty, column-structure-only clone of the source data table.
var tableAux = table.Clone();
// Note: .Copy(), by contrast, would clone the data rows also.

// Select the data row to clone, e.g. the 2nd one:
var row = table.Rows[1];

// Import the data row of interest into the aux. table.
// This creates a *shallow clone* of it.
// Note: If you'll be *reusing* the aux. table for single-row cloning later, call
//       tableAux.Clear() first.
tableAux.ImportRow(row);

// Extract the cloned row from the aux. table:
var rowClone = tableAux.Rows[0];

Nota: A clonagem superficial é realizada , que funciona como está com valores de coluna que são instâncias de tipo de valor , mas mais trabalho seria necessário para também criar cópias independentes de valores de coluna contendo instâncias de tipo de referência (e criar tais cópias independentes nem sempre é possível )

mklement0
fonte
1

Parece que você não quer manter todo o DataTable como uma cópia, porque você só precisa de algumas linhas, certo? Se você tem uma creteria que pode especificar com um select na tabela, você pode copiar apenas essas linhas para um array de backup extra de DataRow como

DataRow[] rows = sourceTable.Select("searchColumn = value");

A função .Select () tem várias opções e esta, por exemplo, pode ser lida como um SQL

SELECT * FROM sourceTable WHERE searchColumn = value;

Em seguida, você pode importar as linhas desejadas conforme descrito acima.

targetTable.ImportRows(rows[n])

... para qualquer n válido que desejar, mas as colunas precisam ser as mesmas em cada tabela.

Algumas coisas que você deve saber sobre ImportRow é que haverá erros durante o tempo de execução ao usar chaves primárias!

Primeiro, queria verificar se já existia uma linha que também falhou devido à falta de uma chave primária, mas a verificação sempre falhou. No final, decidi limpar as linhas existentes completamente e importar as linhas que queria novamente.

A segunda questão ajudou a entender o que acontece. A forma como estou usando a função de importação é para duplicar linhas com uma entrada trocada em uma coluna. Percebi que sempre mudou e ainda era uma referência à linha na matriz. Primeiro, tive que importar o original e, em seguida, alterar a entrada desejada.

A referência também explica os erros de chave primária que apareceram quando tentei importar a linha pela primeira vez, pois ela realmente estava dobrada.

Bolle
fonte
-4

Mas para ter certeza de que sua nova linha está acessível na nova tabela, você precisa fechá-la:

DataTable destination = new DataTable(source.TableName);
destination = source.Clone();
DataRow sourceRow = source.Rows[0];
destination.ImportRow(sourceRow);
rdjabarov
fonte
3
Qual é o ponto da primeira linha de código se a segunda linha de código reatribui a variável?
Erik Philips de
Esta resposta poderia ter mais explicação (e eu não sei o que significa fechar a tabela ) e @ErikPhilips tem um ponto ( DataTable destination = source.Clone()deveria servir ), mas caso contrário, esta resposta é perfeitamente adequada e até preferível à .ItemArrayabordagem na resposta aceita.
mklement0