0
votes

I have a DataRow like {"Foo", "Bar"} in a corresponding DataTable with 2 string columns. I want to copy this row to a new DataTable, which has 3 string columns, the 0th of which is a new value that I want to pass-in. So the resulting row should look like {"My", "Foo", "Bar"}.

Rinse, repeat. Another copy operation would go like {"Bob", "Smith"} => {"My", "Bob", "Smith"}.

I tried using the DataRow.ItemArray in an Array.Copy(), and myDataRow.ItemArray.CopyTo(otherDataRow.ItemArray) as well. Then I read that that doesn't work because the ItemArray is kinda Read-Only despite the intellisense telling you otherwise.

And of course I can write my own loop to copy the values column-by-column, but.. Why is this not built into the libraries or something?

Sample-code:

DataTable dtDestination = new DataTable();
DataTable dtSource = new DataTable();

dtSource.Columns.Add("Str1");
dtSource.Columns.Add("Str2");

dtDestination.Columns.Add("Str0");
dtDestination.Columns.Add("Str1");
dtDestination.Columns.Add("Str2");

dtSource.Rows.Add("Foo", "Bar");
dtSource.Rows.Add("Bob", "Smith");

foreach (DataRow drSrc in dtSource.Rows)
{
    DataRow drNew = dtDestination.NewRow();
    drNew["Str0"] = "My";

    //this doesn't work
    Array.Copy(drSrc.ItemArray, 0, drNew.ItemArray, 1, drSrc.ItemArray.Length);

    //this doesn't work either
    drSrc.ItemArray.CopyTo(drNew.ItemArray, 1);

    //I want to add the "new row" to my destination table,
    //*WITH* the contents from the source-row plus the "My" value in the 0th column!
    dtDestination.Rows.Add(drNew);
}
3
What's wrong with iterating? drNew[1] = drSrc[0]; drNew[2] = drSrc[1] - Zer0
That's my point... I can easily do that with a loop, fine. I'm asking why isn't this kind of thing built in to the framework, or at least to some library that one could just call upon. - NateJ
Because its straight forward and easy to do. Will perform better than array copying for example. - Zer0
@Zer0 How would it perform better? It's still O(N), where N = size of array = # of columns in row. But I do see your point, it's trivial to implement oneself -- just seems silly to not have a DataRow.CopyValuesFrom(otherDataRow, startingIndex) or something. - NateJ
Because the ItemArray is already created when you call NewRow. It's adding memory pressure producing more garbage for the GC. The accepted answer is creating 2 arrays per row. As for your example, what if I wanted to copy columns 1, 2 and 4? It's just too specific a use case and iterating is very simple to do. There's no real problem to solve here. - Zer0

3 Answers

1
votes

You cannot set the .ItemArray values without SetValue But you can Set the ItemArray itself

        DataTable dtDestination = new DataTable();
        DataTable dtSource = new DataTable();

        dtSource.Columns.Add("Str1");
        dtSource.Columns.Add("Str2");

        dtDestination.Columns.Add("Str0");
        dtDestination.Columns.Add("Str1");
        dtDestination.Columns.Add("Str2");

        dtSource.Rows.Add("Foo", "Bar");
        dtSource.Rows.Add("Bob", "Smith");

        foreach (DataRow drSrc in dtSource.Rows)
        {
            DataRow drNew = dtDestination.NewRow();
            var array = new object[drSrc.ItemArray.Length];
            array[0] = "My";
            Array.Copy(drSrc.ItemArray, 0, array, 1, drSrc.ItemArray.Length);
            drNew.ItemArray = array;
            dtDestination.Rows.Add(drNew);
        }

And you should add Testvalues to the Source, not Destination Table...

1
votes

Create an extension method:

public static void CopyValuesFrom(this DataRow me, DataRow copyFrom, int insertIndex = 0, int copyIndex = 0, int count = 0)
{
    if (count == 0)
        count = Math.Min(copyFrom.ItemArray.Length - copyIndex, me.ItemArray.Length - insertIndex);
    for (var i = 0; i < count; i++)
        me[insertIndex + i] = copyFrom[copyIndex + i];
}

Do the copy:

drNew.CopyValuesFrom(drSrc, 1);
0
votes

There is a straightfoward method to do that, just use ImportRow method and additionally after this supply value of additional column