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();