308 votes

Pouvez-vous obtenir les noms des colonnes à partir d'un SqlDataReader ?

Après m'être connecté à la base de données, puis-je obtenir le nom de toutes les colonnes qui ont été renvoyées dans ma demande d'accès à la base de données ? SqlDataReader ?

514voto

Rob Stevenson-Leggett Points 13266
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();

80 votes

C'est fou qu'il n'y ait pas d'interface énumérable qui permette d'itérer dans les colonnes.

66 votes

Un peu plus court : columns = Enumerable.Range(0, reader.FieldCount) .Select(reader.GetName).ToList();

2 votes

Cela fonctionne très bien. J'ai également découvert que les noms de mes colonnes étaient tous en majuscules, à moins que je n'utilise des guillemets autour du nom de la colonne. SELECT id AS "MyId" FROM table;

84voto

Stephen Wrighton Points 15904

Il existe un GetName sur la fonction SqlDataReader qui accepte l'index de la colonne et renvoie le nom de la colonne.

Inversement, il existe un GetOrdinal qui prend un nom de colonne et renvoie l'index de la colonne.

3 votes

Il y a deux raisons à cela : premièrement, l'expéditeur initial 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 que la simple existence de la fonctionnalité. Personnellement, c'est la réponse de Steven Lyons que je préfère car elle ne parle pas seulement de GetName mais aussi de FieldType et DataType.

2 votes

GetOrdinal était parfait. Je cherchais GetName mais une solution beaucoup plus propre pour mon problème avec GetOrdinal .

55voto

Steven Lyons Points 5481

Vous pouvez obtenir les noms des colonnes à 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
  }

19voto

nawfal Points 13500

Déjà mentionné. Juste un LINQ réponse :

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

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

0 votes

Existe-t-il un moyen de faire cela avec les valeurs ?

0 votes

@TravisHeeter Je ne vous comprends pas. Trouver les noms des colonnes à partir des valeurs de quoi ?

0 votes

Je veux dire juste une façon orientale d'obtenir les valeurs dans le jeu de résultat dans une liste, ou peut-être la chose entière à un objet IEnumerable<dynamic>.

7voto

Yakir Manor Points 1725

Si vous voulez uniquement les noms des colonnes, vous pouvez le 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 bien mon complément AdoHelper. Cet ajout est idéal si vous avez une requête d'une seule ligne et que vous ne voulez pas avoir à gérer un tableau de données dans votre code. Il renvoie un dictionnaire insensible à la casse des noms et 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 votes

throw ex; est une mauvaise pratique.

2 votes

C'est juste un exemple

6 votes

Asawyer, tu devrais au moins dire pourquoi. Je suppose que vous allez dire que vous devriez utiliser "throw ;" à la place afin de ne pas perdre les détails de la trace originale de strack.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X