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?

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

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.


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
  }

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.


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

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

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


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();
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.