Вы можете получить таблицу схем из вашего SqlDataReader dr
, чтобы получить имена столбцов, сохранить имена в List<string>
и добавить их в виде столбцов на новый DataTable
, а затем заполнить это DataTable
, используя индексацию на dr
с именами из списка:
DataSet ds = new DataSet();
DataTable dtSchema = dr.GetSchemaTable();
DataTable dt = new DataTable();
List<DataColumn> listCols = new List<DataColumn>();
List<DataColumn> listTypes = new List<DataColumn>();
if (dtSchema != null)
{
foreach (DataRow drow in dtSchema.Rows)
{
string columnName = System.Convert.ToString(drow["ColumnName"]);
DataColumn column = new DataColumn(columnName, (Type)(drow["DataType"]));
listCols.Add(column);
listTypes.Add(drow["DataType"].ToString()); // necessary in order to record nulls
dt.Columns.Add(column);
}
}
// Read rows from DataReader and populate the DataTable
if (dr.HasRows)
{
while (dr.Read())
{
DataRow dataRow = dt.NewRow();
for (int i = 0; i < listCols.Count; i++)
{
if (!dr.IsDBNull[i])
{
// If your query will go against a table with null CLOB fields
// and that column is the 5th column...
if (strSQL == "SELECT * FROM TableWithNullCLOBField" && i == 4)
dataRow[((DataColumn)listCols[i])] = dr.GetOracleClob(i).Value;
// If you might have decimal values of null...
// I found dr.GetOracleDecimal(i) and dr.GetDecimal(i) do not work
else if (listTypes[i] == System.Decimal)
dataRow[((DataColumn)listCols[i])] = dr.GetFloat(i);
else
dataRow[((DataColumn)listCols[i])] = dr[i]; // <-- gets index on dr
}
else // value was null
{
byte[] nullArray = new byte[0];
switch (listTypes[i])
{
case "System.String":
dataRow[((DataColumn)listCols[i])] = String.Empty;
break;
case "System.Decimal":
case "System.Int16": // Boolean
case "System.Int32": // Number
dataRow[((DataColumn)listCols[i])] = 0;
break;
case "System.DateTime":
dataRow[((DataColumn)listCols[i])] = DBNull.Value;
break;
case "System.Byte[]": // Blob
dataRow[((DataColumn)listCols[i])] = nullArray;
break;
default:
dataRow[((DataColumn)listCols[i])] = String.Empty;
break;
}
}
}
dt.Rows.Add(dataRow);
}
ds.Tables.Add(dt);
}
// Put this after everything is closed
if (ds.Tables.Count > 0)
return ds.Tables[0]; // there should only be one table if we got results
else
return null;
Очевидно, вам понадобится блок try...catch...finally
вокруг всего этого для обработки исключений и удаления вашего соединения, а также для использования последнего условия после finally
. Я нашел это полезным для того, чтобы справиться с выяснением, когда у меня были результаты или нет, и избежал проблем с dt.Load(dr)
, которые не работали, когда не было результатов. ds.Fill(adapter)
был не намного лучше, так как он потерпел неудачу, когда я попытался получить таблицу из 97 столбцов и около 80 строк с помощью SELECT * FROM MyTable
. Только код выше смог работать во всех сценариях, для меня.
Первоначально опубликовано Заполнить таблицу данных из устройства чтения данных от sarathkumar. Я предоставил сводку, сжал ее, добавил нулевые проверки и присвоение, если это нулевое значение, и добавил таблицу в DataSet
и добавил условие DataSet
в конце.
ПРИМЕЧАНИЕ. Для тех, кто использует OracleDataReader
, я обнаружил, что вы можете столкнуться с ошибкой, если у вас есть поле NCLOB
или CLOB
, которое является пустым в таблице / наборе результатов, которые вы читаете. Я обнаружил, что если я проверил этот столбец, посмотрев на индекс i
и выполнив dr.GetOracleClob(i)
вместо dr[i]
, я перестал получать исключение. См. Ответ в EF + ODP.NET + CLOB = Значение не может быть пустым - Имя параметра: byteArray? , и я добавил это условие в коде выше, когда if (!dr.IsDBNull[i])
. Точно так же, если у вас есть нулевое поле Decimal
, я должен был проверить его с помощью dr.GetFloat(i);
, так как ни dr.GetOracleDecimal(i);
, ни dr.GetDecimal(i);
, казалось, не могли корректно принять нулевое значение.