Puoi ottenere i nomi delle colonne da un SqlDataReader?


276

Dopo la connessione al database, posso ottenere il nome di tutte le colonne che sono state restituite nel mio SqlDataReader?

Risposte:


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

71
è folle che non ci sia un'interfaccia enumerabile che ti permetta di scorrere le colonne.
JohnFx,

61
Un po 'più breve:columns = Enumerable.Range(0, reader.FieldCount) .Select(reader.GetName).ToList();
Alex,

2
Funziona benissimo. Ho anche scoperto che i nomi delle mie colonne erano tutti in maiuscolo a meno che non usassi le virgolette attorno al nome della colonna. SELECT id AS "MyId" FROM table;
styfle

signore sta restituendo tutti i nomi delle colonne in minuscolo. I nomi delle colonne nella tabella sono tutti maiuscoli come OBJECTID e il lettore restituisce lettere minuscole come objectid
Muneem Habib,

2
sue colonne Dim () Come String = Enumerable.Range (0, cTab.FieldCount) .Select (Function (n) cTab.GetName (n)). ToArray
swe

77

C'è una GetNamefunzione sulla SqlDataReaderquale accetta l'indice di colonna e restituisce il nome della colonna.

Al contrario, esiste un oggetto GetOrdinalche accetta un nome di colonna e restituisce l'indice di colonna.


3
Due motivi: in primo luogo, il poster originale non ha ancora scelto una risposta, e in secondo luogo, ci sono altre risposte che forniscono una descrizione più dettagliata della "soluzione" del problema, quindi solo l'esistenza della funzionalità. Personalmente, mi piace la risposta di Steven Lyons, poiché non solo parla di GetName, ma va anche in FieldType e DataType.
Stephen Wrighton,

1
GetOrdinalera perfetto. Stavo cercando GetName, ma una soluzione molto più pulita per il mio problema con GetOrdinal.
arrivederci,

43

È possibile ottenere i nomi delle colonne da un DataReader.

Ecco 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
  }

15

Già menzionato. Solo una risposta 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();

Il secondo è più pulito e molto più veloce. Anche se si memorizza GetSchemaTablenella cache il primo approccio, l'interrogazione sarà molto lenta.


C'è un modo per farlo con Valori?
Travis Heeter,

@TravisHeeter Non ti capisco. Trova i nomi delle colonne dai valori di cosa?
nawfal,

Intendo solo un modo est per ottenere i valori nel set di risultati in un elenco, o forse il tutto in un oggetto IEnumerable <dynamic>.
Travis Heeter,

@TravisHeeter sì, potrebbe fare reader.Cast<IDataRecord>().ToList(). Credo che potresti usare la dynamicparola chiave lì invece di IDataRecordma senza alcun vantaggio. DataTableè stato progettato per facilitare il caricamento in tempo, quindi è possibile utilizzarlo anche ma si perde il vantaggio del caricamento su richiesta (con il lettore di dati è possibile interrompere il caricamento in qualsiasi momento), ad esempio var dt = new DataTable(); dt.Load(reader); return dt.AsEnumerable().ToList();. Ci sono molte librerie che possono automatizzare questo per voi, trovarli qui stackoverflow.com/questions/11988441 e qui stackoverflow.com/questions/1464883
Nawfal

Ho provato reader.Cast<IEnumerable<dynamic>>e .Cast<dynamic>, ma dice, Cannot convert method group 'Cast' to non-delegate type 'dynamic'. Did you intend to invoke the method?cosa ho fatto di sbagliato lì? (Ho esaminato le tue fonti, ma ti hanno richiesto di conoscere il nome della colonna, cosa che io non conosco)
Travis Heeter,

6

Se vuoi solo i nomi delle colonne, puoi fare:

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"));
    }
}

Ma se hai bisogno solo di una riga, mi piace la mia aggiunta AdoHelper. Questa aggiunta è ottima se si dispone di una query a riga singola e non si desidera gestire la tabella di dati nel codice. Restituisce un dizionario senza distinzione tra maiuscole e minuscole di nomi e valori di colonne.

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;
}

1
throw ex;è la peggiore pratica.
asawyer

2
è solo un esempio
Yakir Manor

5
Asawyer, dovresti almeno dire il perché. Suppongo che dirai che dovresti usare "lancio"; invece in modo da non perdere i dettagli della traccia strack originale.
Brent Rittenhouse,


3

Utilizzare un metodo di estensione:

    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;
    }

2

Sicuro che puoi.


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

}

Questo è originariamente da: http://www.dotnetjunkies.ddj.com/Article/B82A22D1-8437-4C7A-B6AA-C6C9BE9DB8A6.dcik


1

È più facile raggiungerlo in 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();
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.