131

I'm looking for a simple way to make a clone of a DataRow. Kind of like taking a snapshot of that Row and saving it. The values of original Row are then free to change but we still have another saved copy which doesn't change. Is this the correct way to do it?

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

Will this just set Snapshot's ItemArray reference to point to the one in Source or does it actually make a separate copy? Should I do this instead?

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

EDIT: I don't think the second code snippet actually compiles.

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Paul Matthews
  • 2,164
  • 5
  • 20
  • 29
  • I'm not sure i understand, you want to copy a datarow from one table to another table? If so i believe using DataTable.ImportRow is what you are after. – Mo Patel Aug 19 '12 at 07:50
  • Ok, I see that my question needs re-working now – Paul Matthews Aug 19 '12 at 07:58
  • 2
    Note that in some scenarios you may not need to do this because the datarow itself supports transactional editing with BeginEdit/EndEdit/CancelEdit; also you can call .RejectChanges on it. – peterG Mar 25 '14 at 02:54

5 Answers5

213

You can use ImportRow method to copy Row from DataTable to DataTable with the same schema:

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

Update:

With your new Edit, I believe:

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

will work

cuongle
  • 74,024
  • 28
  • 151
  • 206
  • Apparently Clone() only provides a shallow copy. Do you think that will be enough to create an identical copy or is a deep clone required? – Paul Matthews Aug 19 '12 at 11:08
  • 6
    @PaulMatthews: Luckily DataTable contains value types, not ref type, so shallow copy in value type os the same with deep copy – cuongle Aug 19 '12 at 14:09
  • 18
    For people finding this post i'll add the following as i have been asked often so i guess other people might be confused. Clone copy the structure only, Copy copy the structure then the data. That is being said another easy way to copy data once both table instantiated is to create a new row in destination table and use the following : `destRow.ItemArray = sourceRow.ItemArray` then simple add the row back with `destTable.Rows.Add(destRow);` – Franck Mar 18 '14 at 12:04
  • 1
    I'm trying to use this method for getting a clone of a datarow. I do following steps, then I clear the datatable that contains source row and now I have a source row with blank fields. – Sergеу Isupov Oct 09 '15 at 06:58
  • I found that using the ImportRow method worked for me, where the NewRow method did not. – OldDog Feb 24 '17 at 21:47
  • @cuongle: There seems to be no restriction on storing _reference types_ in data tables, at least currently. Was that different in earlier .NET versions? – mklement0 Nov 11 '19 at 16:56
5

Note: cuongle's helfpul answer has all the ingredients, but the solution can be streamlined (no need for .ItemArray) and can be reframed to better match the question as asked.

To create an (isolated) clone of a given System.Data.DataRow instance, you can do the following:

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

Note: Shallow cloning is performed, which works as-is with column values that are value type instances, but more work would be needed to also create independent copies of column values containing reference type instances (and creating such independent copies isn't always possible).

mklement0
  • 382,024
  • 64
  • 607
  • 775
1

It seems you don't want to keep the whole DataTable as a copy, because you only need some rows, right? If you got a creteria you can specify with a select on the table, you could copy just those rows to an extra backup array of DataRow like

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

The .Select() function got several options and this one e.g. can be read as a SQL

SELECT * FROM sourceTable WHERE searchColumn = value;

Then you can import the rows you want as described above.

targetTable.ImportRows(rows[n])

...for any valid n you like, but the columns need to be the same in each table.

Some things you should know about ImportRow is that there will be errors during runtime when using primary keys!

First I wanted to check whether a row already existed which also failed due to a missing primary key, but then the check always failed. In the end I decided to clear the existing rows completely and import the rows I wanted again.

The second issue did help to understand what happens. The way I'm using the import function is to duplicate rows with an exchanged entry in one column. I realized that it always changed and it still was a reference to the row in the array. I first had to import the original and then change the entry I wanted.

The reference also explains the primary key errors that appeared when I first tried to import the row as it really was doubled up.

Bolle
  • 51
  • 3
1

You can create an Extension for the class "DataTable" to create clones and add them to the table easy:

Example usage

DataTable dataTable; // given and contains rows

DataRow row = dataTable.Rows[0]; // Choose one row

// Only create the clone
DataRow clonedRow = dataTable.Clone(row);

// Create the clone and add it to the table
DataRow clonedRowAdded = dataTable.CloneAndAdd(row);

Extension handling this as follows

namespace CustomExtensions
{
    public static class DataTableExtensions
    {
        /// <summary>
        /// Operation: Clone sourceRow and add to destinationDataTable
        /// </summary>
        static public DataRow CloneAndAdd(this DataTable destinationDataTable,
            DataRow sourceRow)
        {
            DataRow clonedRow = destinationDataTable.Clone(sourceRow);
            destinationDataTable.Rows.Add(clonedRow);
            return clonedRow;
        }

        /// <summary>
        /// Operation: Clone sourceRow by destinationDataTable
        /// </summary>
        static public DataRow Clone(this DataTable destinationDataTable, 
            DataRow sourceRow)
        {
            DataRow clonedRow = destinationDataTable.NewRow();
            clonedRow.ItemArray = (object[])sourceRow.ItemArray.Clone();

            return clonedRow;
        }
    }
}
Reza Heidari
  • 1,192
  • 2
  • 18
  • 23
Ralf Peine
  • 11
  • 2
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Apr 27 '22 at 09:09
-3

But to make sure that your new row is accessible in the new table, you need to close the table:

DataTable destination = new DataTable(source.TableName);
destination = source.Clone();
DataRow sourceRow = source.Rows[0];
destination.ImportRow(sourceRow);
Erik Philips
  • 53,428
  • 11
  • 128
  • 150
rdjabarov
  • 21
  • 1
  • 5
    What is the point of the first line of code if the second line of code re-assigns the variable? – Erik Philips Oct 10 '18 at 21:23
  • This answer could use more explanation (and I don't know what _need to close the table_ means) and @ErikPhilips has a point (`DataTable destination = source.Clone()` should do), but otherwise this answer is perfectly fine and even preferable to the `.ItemArray` approach in the accepted answer. – mklement0 Nov 12 '19 at 19:05