Czy możesz uzyskać nazwy kolumn z SqlDataReader?

276

Czy po połączeniu się z bazą danych mogę uzyskać nazwę wszystkich kolumn, które zostały zwrócone w mojej bazie SqlDataReader?

Blankman
źródło

Odpowiedzi:

460
var reader = cmd.ExecuteReader();

var columns = new List<string>();

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

lub

var columns = Enumerable.Range(0, reader.FieldCount).Select(reader.GetName).ToList();
Rob Stevenson-Leggett
źródło
71
to szalone, że nie ma wyliczalnego interfejsu, który pozwalałby na iterację po kolumnach.
JohnFx
61
Nieco krótszy:columns = Enumerable.Range(0, reader.FieldCount) .Select(reader.GetName).ToList();
Alex
2
To działa świetnie. Dowiedziałem się również, że wszystkie nazwy kolumn są wielkie, chyba że użyłem cudzysłowu wokół nazwy kolumny. SELECT id AS "MyId" FROM table;
styfle
panie, zwraca wszystkie nazwy kolumn małymi literami. Nazwy kolumn w tabeli są wielkie jak OBJECTID, a czytelnik zwraca małe litery jak objectid
Muneem Habib
2
jego Dim kolumny () As String = Enumerable.Range (0, cTab.FieldCount) .Wybierz (Function (n) cTab.GetName (n)). ToArray
swe
77

Istnieje GetNamefunkcja, SqlDataReaderktóra akceptuje indeks kolumny i zwraca nazwę kolumny.

I odwrotnie, istnieje taki, GetOrdinalktóry pobiera nazwę kolumny i zwraca indeks kolumny.

Stephen Wrighton
źródło
3
Dwa powody: po pierwsze, oryginalny plakat nie wybrał jeszcze odpowiedzi, a po drugie, istnieją inne odpowiedzi, które podają bardziej szczegółowy opis „rozwiązania” problemu, a jedynie samą funkcjonalność. Osobiście najbardziej podoba mi się odpowiedź Stevena Lyonsa, ponieważ nie tylko mówi o GetName, ale także o FieldType i DataType.
Stephen Wrighton
1
GetOrdinalbyło perfekcyjne. Szukałem GetName, ale o wiele czystszego rozwiązania mojego problemu z GetOrdinal.
goodeye,
43

Nazwy kolumn można uzyskać z czytnika danych.

Oto ważna część:

  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
źródło
15

Już wspomniane. Tylko odpowiedź 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();

Drugi jest czystszy i znacznie szybszy. Nawet jeśli buforujesz GetSchemaTablew pierwszym podejściu, zapytania będą bardzo powolne.

nawfal
źródło
Czy można to zrobić za pomocą Wartości?
Travis Heeter,
@TravisHeeter Nie rozumiem cię. Znajdź nazwy kolumn z wartości czego?
nawfal
Mam na myśli tylko wschodni sposób na umieszczenie wartości w zestawie wyników na liście, a może całą rzecz do IEnumerable <dynamic> obiektu.
Travis Heeter
@TravisHeeter tak może zrobić reader.Cast<IDataRecord>().ToList() . Uważam, że możesz użyć dynamicsłowa kluczowego zamiast, IDataRecordale bez korzyści. DataTablezostał zaprojektowany, aby ułatwić jednorazowe ładowanie, więc możesz z niego skorzystać, ale tracisz korzyści z ładowania na żądanie (z czytnikiem danych możesz zatrzymać ładowanie w dowolnym momencie), na przykład var dt = new DataTable(); dt.Load(reader); return dt.AsEnumerable().ToList();. Istnieje wiele bibliotek, które mogą zautomatyzować to za Ciebie, znajdź je tutaj stackoverflow.com/questions/11988441 i tutaj stackoverflow.com/questions/1464883
nawfal
Próbowałem reader.Cast<IEnumerable<dynamic>>i .Cast<dynamic>, ale mówi, Cannot convert method group 'Cast' to non-delegate type 'dynamic'. Did you intend to invoke the method?co zrobiłem tam źle? (Spojrzałem na twoje źródła, ale wymagały od ciebie nazwy kolumny, której nie znam)
Travis Heeter
6

Jeśli chcesz tylko nazwy kolumn, możesz:

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

Ale jeśli potrzebujesz tylko jednego wiersza, podoba mi się mój dodatek AdoHelper. Ten dodatek jest świetny, jeśli masz jednowierszowe zapytanie i nie chcesz zajmować się tabelą danych w swoim kodzie. Zwraca słownik nazw i wartości kolumn bez rozróżniania wielkości liter.

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;
}
Yakir Manor
źródło
1
throw ex;jest najgorszą praktyką.
asawyer
2
to tylko przykład
Yakir Manor
5
Asawyer, powinieneś przynajmniej powiedzieć dlaczego. Zakładam, że powiesz, że powinieneś użyć „rzuć”; zamiast tego, aby nie stracić oryginalnych szczegółów śledzenia ścieżki.
Brent Rittenhouse
3

Użyj metody rozszerzenia:

    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
źródło
2

Na pewno możesz.


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

}

Pochodzi z: http://www.dotnetjunkies.ddj.com/Article/B82A22D1-8437-4C7A-B6AA-C6C9BE9DB8A6.dcik

Jeremiasz Peschka
źródło
1

Łatwiej jest to osiągnąć w 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
źródło