1

We have a huge list (say 100,000) which needs to be converted to DataTable for SqlBulkcopy.

Can you guide what could be the fastest way to do this without using for loop? For now we are doing it like - in below code listDos is object list

using (var dataTable = new DataTable(dataTableName))
{
    dataTable.Locale = CultureInfo.CurrentCulture;
    var columns = new[]
        {
             new DataColumn("Id", typeof(int)),
             new DataColumn("FkId", typeof(int)),
             new DataColumn("Status", typeof(string)),
             new DataColumn("RecordFrom", typeof(DateTime))
        };

    dataTable.Columns.AddRange(columns);


    foreach (ObjectDo listDo in listDos)
    {
        var row = dataTable.NewRow();

        if (rebuildDo.Id != null) row["Id"] = rebuildDo.Id;

        if (rebuildDo.FkId!= null) row["FkId"] = rebuildDo.FkId;

        row["Status"] = rebuildDo.Status;

        row["RecordFrom"] = rebuildDo.RecordFrom;

        dataTable.Rows.Add(row);
    }

    return dataTable;
}
13
  • If you want linq please show a linq effort. Also the linq query will not have the syntax of a loop but it does loop (iterate) over all items.. Commented Jan 16, 2018 at 14:20
  • 3
    why "without for loop"? that seems a very arbitrary restriction... since you're dealing with lots of data, it is expected that something somewhere is going to need to loop... Commented Jan 16, 2018 at 14:25
  • I'm voting to close this question as off-topic because there is no problem to solve (only how to improve) and perhaps belongs on another Stack Exchange site. Plus motives are not explained Commented Jan 16, 2018 at 14:26
  • @ScottHannen it's not the loop, it's the duplication of data that will cause problems. Especially if there are a lot of data. Commented Jan 16, 2018 at 14:26
  • @MickyD on the contrary, this is a significant concern when using SqlBulkCopy. If you have 10K items, creating a DataTable with them doubles the memory usage and creates a lot of temporary objects that have to be garbage collected. Commented Jan 16, 2018 at 14:28

1 Answer 1

8

The fastest way would be: not to.

SqlBulkCopy can take an IDataReader. "FastMember" (on NuGet) can expose a List<T> as an IDataReader:

List<ObjectDo> listDos = ...
using(var bcp = new SqlBulkCopy(connection)) 
using(var reader = ObjectReader.Create(listDos,
    "Id", "FkId", "Status", "RecordFrom")) 
{ 
  bcp.DestinationTableName = "SomeTable"; 
  bcp.WriteToServer(reader); 
}

This is now a direct reader over the list: no duplication of all the contents.

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks for the inputs. Tried this and it seems almost three times faster than going with SqlBulkCopy and data table.. Just for curiosity, why ObjectReader is faster?
@Oxygen possibly because it is simpler? DataTable has quite a lot of overhead, including the fact that it actually stores fields vertically rather than horizontally (which it does to avoid having to do lots of boxing) - so you actually get pretty poor memory locality. Note that without seeing a specific performance test: I can only speculate
@Mac. Need one more small help. I have miss match in class properties and table column names, is it mandatory that reader should match table properties? Also if table contains 10 columns, how can I create Object reader with only required 5 columns?
@Oxygen look at bcp.ColumnMappings. Add mapping between the desired source and destination columns.
Thank you so much for all your time and direction.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.