I am trying to convert a DataTable to an IEnumerable. Where T is a custom type I created. I know I can do it by creating a List
but I was thinking if t
If you are producing the DataTable
from an SQL query, have you considered simply using Dapper instead?
Then, instead of making a SqlCommand
with SqlParameters
and a DataTable
and a DataAdapter
and on and on, which you then have to laboriously convert to a class, you just define the class, make the query column names match the field names, and the parameters are bound easily by name. You already have the TankReading
class defined, so it will be really simple!
using Dapper;
// Below can be SqlConnection cast to DatabaseConnection, too.
DatabaseConnection connection = // whatever
IEnumerable<TankReading> tankReadings = connection.Query<TankReading>(
"SELECT * from TankReading WHERE Value = @value",
new { value = "tank1" } // note how `value` maps to `@value`
);
return tankReadings;
Now isn't that awesome? Dapper is very optimized and will give you darn near equivalent performance as reading directly with a DataAdapter
.
If your class has any logic in it at all or is immutable or has no parameterless constructor, then you probably do need to have a DbTankReading
class (as a pure POCO/Plain Old Class Object):
// internal because it should only be used in the data source project and not elsewhere
internal sealed class DbTankReading {
int TankReadingsID { get; set; }
DateTime? ReadingDateTime { get; set; }
int ReadingFeet { get; set; }
int ReadingInches { get; set; }
string MaterialNumber { get; set; }
string EnteredBy { get; set; }
decimal ReadingPounds { get; set; }
int MaterialID { get; set; }
bool Submitted { get; set; }
}
You'd use that like this:
IEnumerable<TankReading> tankReadings = connection
.Query<DbTankReading>(
"SELECT * from TankReading WHERE Value = @value",
new { value = "tank1" } // note how `value` maps to `@value`
)
.Select(tr => new TankReading(
tr.TankReadingsID,
tr.ReadingDateTime,
tr.ReadingFeet,
tr.ReadingInches,
tr.MaterialNumber,
tr.EnteredBy,
tr.ReadingPounds,
tr.MaterialID,
tr.Submitted
});
Despite the mapping work, this is still less painful than the data table method. This also lets you perform some kind of logic, though if the logic is any more than very simple straight-across mapping, I'd put the logic into a separate TankReadingMapper
class.
PagedDataSource objPage = new PagedDataSource();
DataView dataView = listData.DefaultView;
objPage.AllowPaging = true;
objPage.DataSource = dataView;
objPage.PageSize = PageSize;
TotalPages = objPage.PageCount;
objPage.CurrentPageIndex = CurrentPage - 1;
//Convert PagedDataSource to DataTable
System.Collections.IEnumerator pagedData = objPage.GetEnumerator();
DataTable filteredData = new DataTable();
bool flagToCopyDTStruct = false;
while (pagedData.MoveNext())
{
DataRowView rowView = (DataRowView)pagedData.Current;
if (!flagToCopyDTStruct)
{
filteredData = rowView.Row.Table.Clone();
flagToCopyDTStruct = true;
}
filteredData.LoadDataRow(rowView.Row.ItemArray, true);
}
//Here is your filtered DataTable
return filterData;