Pouvez-vous obtenir les noms de colonne à partir d'un SqlDataReader?

276

Après la connexion à la base de données, puis-je obtenir le nom de toutes les colonnes qui ont été renvoyées dans mon SqlDataReader?

Blankman
la source

Réponses:

460
var reader = cmd.ExecuteReader();

var columns = new List<string>();

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

ou

var columns = Enumerable.Range(0, reader.FieldCount).Select(reader.GetName).ToList();
Rob Stevenson-Leggett
la source
71
c'est fou qu'il n'y ait pas d'interface énumérable qui vous permet de parcourir les colonnes.
JohnFx
61
Un peu plus court:columns = Enumerable.Range(0, reader.FieldCount) .Select(reader.GetName).ToList();
Alex
2
Cela fonctionne très bien. J'ai également découvert que les noms de mes colonnes étaient tous en majuscules, sauf si j'utilisais des guillemets autour du nom de la colonne. SELECT id AS "MyId" FROM table;
styfle
monsieur, il renvoie tous les noms de colonnes en minuscules. Les noms de colonne dans le tableau sont tous en majuscules comme OBJECTID et le lecteur retourne des minuscules comme objectid
Muneem Habib
2
ses colonnes Dim () As String = Enumerable.Range (0, cTab.FieldCount) .Select (Function (n) cTab.GetName (n)). ToArray
swe
77

Il y a une GetNamefonction sur le SqlDataReaderqui accepte l'index de colonne et retourne le nom de la colonne.

Inversement, il y a un GetOrdinalqui prend un nom de colonne et retourne l'index de colonne.

Stephen Wrighton
la source
3
Deux raisons: premièrement, l'affiche originale n'a pas encore choisi de réponse, et deuxièmement, il y a d'autres réponses qui donnent une description plus détaillée de la `` solution '' du problème, puis juste l'existence de la fonctionnalité. Personnellement, j'aime la réponse de Steven Lyons, car non seulement elle parle de GetName mais elle va également dans FieldType et DataType.
Stephen Wrighton
1
GetOrdinalétait parfait. Je cherchais GetName, mais une solution beaucoup plus propre pour mon problème GetOrdinal.
goodeye
43

Vous pouvez obtenir les noms de colonne à partir d'un DataReader.

Voici la partie 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
la source
15

Déjà mentionné. Juste une réponse 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();

Le second est plus propre et beaucoup plus rapide. Même si vous mettez en cache GetSchemaTabledans la première approche, l'interrogation va être très lente.

nawfal
la source
Existe-t-il un moyen de le faire avec les valeurs?
Travis Heeter
@TravisHeeter Je ne vous comprends pas. Trouver les noms des colonnes à partir des valeurs de quoi?
nawfal
Je veux dire juste une façon orientale d'obtenir les valeurs du jeu de résultats dans une liste, ou peut-être le tout à un objet IEnumerable <dynamic>.
Travis Heeter
@TravisHeeter oui pourrait le faire reader.Cast<IDataRecord>().ToList(). Je pense que vous pouvez utiliser un dynamicmot clé à la place, IDataRecordmais sans aucun avantage. DataTablea été conçu pour faciliter le chargement ponctuel, vous pouvez donc l'utiliser aussi mais vous perdez l'avantage du chargement à la demande (avec le lecteur de données, vous pouvez arrêter le chargement à tout moment), comme var dt = new DataTable(); dt.Load(reader); return dt.AsEnumerable().ToList();. Il existe de nombreuses bibliothèques qui peuvent automatiser cela pour vous, trouvez-les ici stackoverflow.com/questions/11988441 et ici stackoverflow.com/questions/1464883
nawfal
J'ai essayé reader.Cast<IEnumerable<dynamic>>et .Cast<dynamic>, mais ça dit, Cannot convert method group 'Cast' to non-delegate type 'dynamic'. Did you intend to invoke the method?qu'est-ce que j'ai fait de mal là-bas? (J'ai regardé vos sources, mais elles vous demandaient de connaître le nom de la colonne, ce que je ne sais pas)
Travis Heeter
6

Si vous ne voulez que les noms de colonne, vous pouvez faire:

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

Mais si vous n'avez besoin que d'une seule ligne, j'aime mon ajout AdoHelper. Cet ajout est idéal si vous avez une requête sur une seule ligne et que vous ne souhaitez pas traiter le tableau de données dans votre code. Il renvoie un dictionnaire insensible à la casse des noms et des valeurs des colonnes.

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;
}
Manoir Yakir
la source
1
throw ex;est une pire pratique.
avocat
2
c'est juste un exemple
Yakir Manor
5
Avocat, vous devriez au moins dire pourquoi. Je suppose que vous allez dire que vous devez utiliser "throw"; au lieu de cela, afin de ne pas perdre les détails de la trace de trace d'origine.
Brent Rittenhouse
3

Utilisez une méthode d'extension:

    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
la source
2

Vous le pouvez certainement.


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

}

Il s'agit à l'origine de: http://www.dotnetjunkies.ddj.com/Article/B82A22D1-8437-4C7A-B6AA-C6C9BE9DB8A6.dcik

Jeremiah Peschka
la source
1

Il est plus facile de le réaliser 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
la source