Search code examples
c#linqdatatable

Pass every column of every row of a datatable to a method using Linq?


I am seeking a way of avoiding nested foreach loops for a task. I want to pass the column name and column value to a method, for every column and every row of a datatable. The method is for logging. I want the name and value to be concatenated as part of the process so the resulting string is the log message string argument. Furthermore, I'd like the structure of the datatable to be unknown. I am thinking Linq can do this. However, after writing datatable.AsEnumerable() my mind goes blank.


Solution

  • You can do this by using the ItemArray of each DataRow to process all the column values in each row.

    First collect all the column names together, so you won't have to keep doing it:

    var colnames = dt.Columns
                     .Cast<DataColumn>()
                     .Select(dc => dc.ColumnName)
                     .ToList();
    

    Then combine the column names with the row values for each row:

    var ans = dt.AsEnumerable() // foreach DataRow in DataTable
                .Select(r => r.ItemArray // foreach item in DataRow.ItemArray
                              .Zip(colnames, // foreach colname in DataTable.Columns.ColumnName
                                   (item, colname) => $"{colname} = {item}") // ColumnName = ColumnValue
                       );
    

    If you want to pass the result to a logging function, just use foreach with SelectMany to flatten:

    foreach (var msg in ans.SelectMany(r => r))
        LogData(logType, msg);