Простой способ скопировать или клонировать DataRow?

118

Я ищу простой способ сделать клон DataRow. Это как сделать снимок этой строки и сохранить его. Значения исходной строки могут быть изменены, но у нас все еще есть другая сохраненная копия, которая не изменяется. Это правильный способ сделать это?

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

Будет ли это просто устанавливать ссылку на ItemArray моментального снимка так, чтобы она указывала на ссылку в Source, или она действительно создает отдельную копию? Должен ли я сделать это вместо этого?

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

EDIT: я не думаю, что второй фрагмент кода действительно компилируется.

Пол Мэтьюз
источник
Я не уверен, что понимаю, вы хотите скопировать строку данных из одной таблицы в другую? Если это так, я считаю, что использование DataTable.ImportRow - это то, что вам нужно.
Мо Патель,
Хорошо, я вижу, что сейчас мой вопрос требует доработки
Пол Мэтьюз
2
Обратите внимание, что в некоторых сценариях вам может не потребоваться это делать, поскольку поток данных сам поддерживает редактирование транзакций с помощью BeginEdit / EndEdit / CancelEdit; также вы можете вызвать .RejectChanges на нем.
peterG

Ответы:

185

Вы можете использовать ImportRowметод для копирования строки из DataTable в DataTable с той же схемой:

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

Обновить:

С вашим новым Edit, я считаю:

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

буду работать

cuongle
источник
По-видимому, Clone () предоставляет только мелкую копию. Как вы думаете, этого будет достаточно для создания идентичной копии или требуется глубокий клон?
Пол Мэтьюз,
5
@PaulMatthews: К счастью, DataTable содержит типы значений, а не тип ref, поэтому неглубокая копия в типе значения аналогична глубокой копии
cuongle
16
Для людей, нашедших этот пост, я добавлю следующее, поскольку меня часто спрашивали, поэтому я думаю, другие люди могут быть сбиты с толку. Клонировать - копировать только структуру, Копировать - копировать структуру, а затем данные. Говорят, что еще один простой способ скопировать данные после создания экземпляров обеих таблиц - создать новую строку в целевой таблице и использовать следующее: destRow.ItemArray = sourceRow.ItemArrayзатем просто добавить строку обратно с помощьюdestTable.Rows.Add(destRow);
Franck
1
Пытаюсь использовать этот метод для получения клона datarow. Я делаю следующие шаги, затем очищаю таблицу данных, содержащую исходную строку, и теперь у меня есть исходная строка с пустыми полями.
Сергей Исупов
Я обнаружил, что у меня работает метод ImportRow, тогда как метод NewRow - нет.
OldDog
2

Примечание. В ответе cuongle helfpul есть все ингредиенты, но решение можно упростить (в этом нет необходимости .ItemArray) и изменить структуру, чтобы лучше соответствовать заданному вопросу.

Чтобы создать (изолированный) клон данного System.Data.DataRowэкземпляра , вы можете сделать следующее:

// 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];

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

mklement0
источник
1

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

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

Функция .Select () имеет несколько опций, и этот, например, можно читать как SQL

SELECT * FROM sourceTable WHERE searchColumn = value;

Затем вы можете импортировать нужные строки, как описано выше.

targetTable.ImportRows(rows[n])

... для любого допустимого n, которое вам нравится, но столбцы должны быть одинаковыми в каждой таблице.

Что вам следует знать о ImportRow, так это то, что при использовании первичных ключей во время выполнения будут возникать ошибки!

Сначала я хотел проверить, существует ли уже строка, что также не удалось из-за отсутствия первичного ключа, но тогда проверка всегда терпела неудачу. В конце концов я решил полностью очистить существующие строки и снова импортировать нужные строки.

Вторая проблема действительно помогла понять, что происходит. Я использую функцию импорта для дублирования строк с измененной записью в одном столбце. Я понял, что он всегда менялся и все еще оставался ссылкой на строку в массиве. Сначала мне пришлось импортировать оригинал, а затем изменить запись, которую я хотел.

В справке также объясняются ошибки первичного ключа, которые возникли, когда я впервые попытался импортировать строку, поскольку она действительно была увеличена вдвое.

Bolle
источник
-4

Но чтобы убедиться, что ваша новая строка доступна в новой таблице, вам нужно закрыть таблицу:

DataTable destination = new DataTable(source.TableName);
destination = source.Clone();
DataRow sourceRow = source.Rows[0];
destination.ImportRow(sourceRow);
rdjabarov
источник
3
В чем смысл первой строки кода, если вторая строка кода переназначает переменную?
Эрик Филипс
В этом ответе можно было бы использовать дополнительные объяснения (и я не знаю, что означает необходимость закрытия таблицы ), и @ErikPhilips имеет смысл ( DataTable destination = source.Clone()должен), но в остальном этот ответ совершенно прекрасен и даже предпочтительнее .ItemArrayподхода в принятом ответе.
mklement0