¿Puedes obtener los nombres de columna de un SqlDataReader?

276

Después de conectarme a la base de datos, ¿puedo obtener el nombre de todas las columnas que se devolvieron en mi SqlDataReader?

Blankman
fuente

Respuestas:

460
var reader = cmd.ExecuteReader();

var columns = new List<string>();

for(int i=0;i<reader.FieldCount;i++)
{
   columns.Add(reader.GetName(i));
}

o

var columns = Enumerable.Range(0, reader.FieldCount).Select(reader.GetName).ToList();
Rob Stevenson-Leggett
fuente
71
Es una locura que no haya una interfaz enumerable que le permita recorrer las columnas.
JohnFx
61
Un poco más corto:columns = Enumerable.Range(0, reader.FieldCount) .Select(reader.GetName).ToList();
Alex
2
Esto funciona muy bien. También descubrí que los nombres de mis columnas estaban en mayúsculas a menos que usara comillas alrededor del nombre de la columna. SELECT id AS "MyId" FROM table;
styfle
sir está devolviendo todos los nombres de columna en minúsculas. Los nombres de las columnas en la tabla están en mayúsculas como OBJECTID y el lector está regresando en minúsculas como objectid
Muneem Habib
2
sus columnas Dim () As String = Enumerable.Range (0, cTab.FieldCount) .Select (Function (n) cTab.GetName (n)). ToArray
swe
77

Hay una GetNamefunción en la SqlDataReaderque acepta el índice de columna y devuelve el nombre de la columna.

Por el contrario, hay una GetOrdinalque toma el nombre de una columna y devuelve el índice de la columna.

Stephen Wrighton
fuente
3
Dos razones: en primer lugar, el póster original aún no ha elegido una respuesta y, en segundo lugar, hay otras respuestas que dan una descripción más detallada de la 'solución' del problema y luego solo la existencia de la funcionalidad. Personalmente, me gusta la respuesta de Steven Lyons, ya que no solo habla sobre GetName sino que también entra en FieldType y DataType.
Stephen Wrighton el
1
GetOrdinalfue perfecto. Estaba buscando GetName, pero una solución mucho más limpia para mi problema con GetOrdinal.
goodeye
43

Puede obtener los nombres de columna de un DataReader.

Aquí está la parte importante:

  for (int col = 0; col < SqlReader.FieldCount; col++)
  {
    Console.Write(SqlReader.GetName(col).ToString());         // Gets the column name
    Console.Write(SqlReader.GetFieldType(col).ToString());    // Gets the column type
    Console.Write(SqlReader.GetDataTypeName(col).ToString()); // Gets the column database type
  }
Steven Lyons
fuente
15

Ya mencionado. Solo una respuesta LINQ :

var columns = reader.GetSchemaTable().Rows
                                     .Cast<DataRow>()
                                     .Select(r => (string)r["ColumnName"])
                                     .ToList();

//Or

var columns = Enumerable.Range(0, reader.FieldCount)
                        .Select(reader.GetName)
                        .ToList();

El segundo es más limpio y mucho más rápido. Incluso si almacena GetSchemaTableen caché en el primer enfoque, la consulta será muy lenta.

nawfal
fuente
¿Hay alguna manera de hacer esto con los valores?
Travis Heeter
@TravisHeeter No te entiendo. ¿Encontrar nombres de columnas a partir de valores de qué?
nawfal
Me refiero a solo una forma este de obtener los valores en el conjunto de resultados en una lista, o tal vez todo en un objeto IEnumerable <dynamic>.
Travis Heeter
@TravisHeeter sí podría hacer reader.Cast<IDataRecord>().ToList(). Creo que podría usar dynamicpalabras clave allí en lugar de hacerlo, IDataRecordpero sin ningún beneficio. DataTablefue diseñado para facilitar la carga de una vez, por lo que también puede usarlo, pero pierde el beneficio de cargar a pedido (con el lector de datos puede detener la carga en cualquier momento), como var dt = new DataTable(); dt.Load(reader); return dt.AsEnumerable().ToList();. Hay muchas bibliotecas que pueden automatizar esto para usted, encuéntrelas aquí stackoverflow.com/questions/11988441 y aquí stackoverflow.com/questions/1464883
nawfal
Lo intenté reader.Cast<IEnumerable<dynamic>>y .Cast<dynamic>, pero dice, Cannot convert method group 'Cast' to non-delegate type 'dynamic'. Did you intend to invoke the method?¿qué hice mal allí? (Miré sus fuentes, pero le exigieron que supiera el nombre de la columna, lo cual no sé)
Travis Heeter
6

Si solo desea los nombres de columna, puede hacer:

List<string> columns = new List<string>();
using (SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SchemaOnly))
{
    DataTable dt = reader.GetSchemaTable();
    foreach (DataRow row in dt.Rows)
    {
        columns.Add(row.Field<String>("ColumnName"));
    }
}

Pero si solo necesita una fila, me gusta mi adición AdoHelper. Esta adición es excelente si tiene una consulta de una sola línea y no desea tratar con la tabla de datos en su código. Está devolviendo un diccionario de mayúsculas y minúsculas de nombres y valores de columna.

public static Dictionary<string, string> ExecuteCaseInsensitiveDictionary(string query, string connectionString, Dictionary<string, string> queryParams = null)
{
    Dictionary<string, string> CaseInsensitiveDictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
    try
    {
        using (SqlConnection conn = new SqlConnection(connectionString))
        {
            conn.Open();
            using (SqlCommand cmd = new SqlCommand())
            {
                cmd.Connection = conn;
                cmd.CommandType = CommandType.Text;
                cmd.CommandText = query;

                // Add the parameters for the SelectCommand.
                if (queryParams != null)
                    foreach (var param in queryParams)
                        cmd.Parameters.AddWithValue(param.Key, param.Value);

                using (SqlDataReader reader = cmd.ExecuteReader())
                {
                    DataTable dt = new DataTable();
                    dt.Load(reader);
                    foreach (DataRow row in dt.Rows)
                    {
                        foreach (DataColumn column in dt.Columns)
                        {
                            CaseInsensitiveDictionary.Add(column.ColumnName, row[column].ToString());
                        }
                    }
                }
            }
            conn.Close();
        }
    }
    catch (Exception ex)
    {
        throw ex;
    }
    return CaseInsensitiveDictionary;
}
Mansión Yakir
fuente
1
throw ex;Es una peor práctica.
asawyer
2
es solo un ejemplo
Yakir Manor el
55
Asawyer, al menos deberías decir por qué. Asumo que vas a decir que deberías usar "tirar"; en su lugar, para que no pierda los detalles originales del seguimiento de la banda.
Brent Rittenhouse
3

Use un método de extensión:

    public static List<string> ColumnList(this IDataReader dataReader)
    {
        var columns = new List<string>();
        for (int i = 0; i < dataReader.FieldCount; i++)
        {
            columns.Add(dataReader.GetName(i));
        }
        return columns;
    }
Rob Sedgwick
fuente
2

Seguro que puedes.


protected void GetColumNames_DataReader()
{
  System.Data.SqlClient.SqlConnection SqlCon = new System.Data.SqlClient.SqlConnection("server=localhost;database=northwind;trusted_connection=true");
  System.Data.SqlClient.SqlCommand SqlCmd = new System.Data.SqlClient.SqlCommand("SELECT * FROM Products", SqlCon);

  SqlCon.Open();

  System.Data.SqlClient.SqlDataReader SqlReader = SqlCmd.ExecuteReader();
  System.Int32 _columncount = SqlReader.FieldCount;

  System.Web.HttpContext.Current.Response.Write("SqlDataReader Columns");
  System.Web.HttpContext.Current.Response.Write(" ");

  for ( System.Int32 iCol = 0; iCol < _columncount; iCol ++ )
  {
    System.Web.HttpContext.Current.Response.Write("Column " + iCol.ToString() + ": ");
    System.Web.HttpContext.Current.Response.Write(SqlReader.GetName( iCol ).ToString());
    System.Web.HttpContext.Current.Response.Write(" ");
  }

}

Esto es originalmente de: http://www.dotnetjunkies.ddj.com/Article/B82A22D1-8437-4C7A-B6AA-C6C9BE9DB8A6.dcik

Jeremiah Peschka
fuente
1

Es más fácil lograrlo en SQL

var columnsList = dbContext.Database.SqlQuery<string>("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'SCHEMA_OF_YOUE_TABLE' AND TABLE_NAME = 'YOUR_TABLE_NAME'").ToList();
Almett
fuente