Ač to není příliš šťastná situace, může se nám někdy přihodit, že potřebujeme konvertovat SqlDataReader na DataSet.
V .NET Frameworku 1.1 jsou v podstatě dvě základní cesty – buď to udělat ručně, prvek po prvku, nebo si uvědomit, že DataAdapter dělá v podstatě totéž, a už by to tedy mohlo být někde řešeno (v .NET Frameworku 2.0 již je tato funkčnost exponováno prostřednictvím metody DataTable.Load(), viz níže).
Ručně to vypadá např. takto (kód není můj, tak to berte s rezervou):
public static DataSet DataReaderToDataSet( SqlDataReader rd )
{
DataSet ds = new DataSet();
do
{
DataTable st = rd.GetSchemaTable();
DataTable Dt = new DataTable();
if (st != null)
{
for (int i = 0 ; i < st.Rows.Count ; i++)
{
DataRow dr = st.Rows[i];
string columnName = (string)dr["ColumnName"];
DataColumn column = new DataColumn(columnName, (Type)dr["DataType"]);
dt.Columns.Add(column);
}
ds.Tables.Add(dt);
while (rd.Read())
{
DataRow dr = dt.NewRow();
for (int i = 0; i < rd.FieldCount; i++)
dr[i] = rd.GetValue(i);
dt.Rows.Add(dr);
}
}
else
{
DataColumn column = new DataColumn("RowsAffected");
dt.Columns.Add(column);
ds.Tables.Add(dt);
DataRow dr = dt.NewRow();
dr[0] = rd.RecordsAffected;
dt.Rows.Add(dr);
}
}
while (rd.NextResult());
return ds;
}
Mnohem lepší fígl přes DataAdapter spočívá ve zjištění, že třída DbDataAdapter, z které jsou odvozeny všechny specifické DataAdaptery obsahuje metodu protected Fill(DataTable, IDataReader).
Můžeme tedy vytvořit vlastní DataAdapter odvozený od DbDataAdapteru, který tuto metodu použije ke zbudování příslušné tabulky:
public class DataReaderAdapter : DbDataAdapter
{
public int FillFromReader(DataTable dataTable, IDataReader dataReader)
{
return this.Fill(dataTable, dataReader);
}
protected override RowUpdatedEventArgs CreateRowUpdatedEvent(
DataRow dataRow,
IDbCommand command,
StatementType statementType,
DataTableMapping tableMapping)
{
return null;
}
protected override RowUpdatingEventArgs CreateRowUpdatingEvent(
DataRow dataRow,
IDbCommand command,
StatementType statementType,
DataTableMapping tableMapping)
{
return null;
}
protected override void OnRowUpdated(
RowUpdatedEventArgs value)
{
}
protected override void OnRowUpdating(
RowUpdatingEventArgs value)
{
}
}
…a dát DataTable do DataSetu už není problém, případně escalovat SqlDataReader na další rowset a vytáhnout další tabulku. Ostatně DbDataAdapter obsahuje i mnoho další overloadů metody Fill() a můžeme si tak udělat mnohem chytřejší DataReaderAdapter.
Update pro .NET Framework 2.0
.NET Framework 2.0 již tuto problematiku řeší metodou DataTable.Load();