Можете ли вы получить имена столбцов из SqlDataReader?

После подключения к базе данных, могу ли я получить имена всех столбцов, которые были возвращены в моем SqlDataReader?


person Blankman    schedule 25.03.2009    source источник


Ответы (10)


На SqlDataReader есть функция GetName, которая принимает индекс столбца и возвращает имя столбца.

И наоборот, есть GetOrdinal, который принимает имя столбца и возвращает индекс столбца.

person Stephen Wrighton    schedule 25.03.2009
comment
Две причины: во-первых, исходный постер еще не выбрал ответ, а во-вторых, есть другие ответы, которые дают более подробное описание «решения» проблемы, чем просто наличие функциональности. Лично мне больше всего нравится ответ Стивена Лайонса, поскольку в нем не только говорится о GetName, но также идет речь о FieldType и DataType. - person Stephen Wrighton; 26.11.2013
comment
GetOrdinal был идеальным. Я искал GetName, но гораздо более чистое решение моей проблемы с GetOrdinal. - person goodeye; 30.07.2015

Вы можете получить имена столбцов из DataReader.

Вот важная часть:

  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
  }
person Steven Lyons    schedule 25.03.2009

Уже упоминалось. Просто ответ 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();

Второй чище и намного быстрее. Даже если вы кешируете GetSchemaTable в первом подходе, запросы будут очень медленными.

person nawfal    schedule 12.12.2013
comment
Есть ли способ сделать это с помощью ценностей? - person Travis Heeter; 27.07.2015
comment
@TravisHeeter Я тебя не понимаю. Найти имена столбцов из значений чего? - person nawfal; 27.07.2015
comment
Я имею в виду просто восточный способ получить значения в результирующем наборе в список или, возможно, все это в объект IEnumerable ‹dynamic›. - person Travis Heeter; 27.07.2015
comment
@TravisHeeter, да, reader.Cast<IDataRecord>().ToList(). Я считаю, что вы могли бы использовать здесь ключевое слово dynamic вместо IDataRecord, но без всякой пользы. DataTable был разработан для упрощения одноразовой загрузки, поэтому вы тоже можете использовать его, но вы теряете возможность загрузки по запросу (с помощью средства чтения данных вы можете остановить загрузку в любой момент), как var dt = new DataTable(); dt.Load(reader); return dt.AsEnumerable().ToList();. Существует множество библиотек, которые могут автоматизировать это за вас. Их можно найти здесь, stackoverflow.com/questions/11988441 и здесь stackoverflow.com/questions/1464883 - person nawfal; 27.07.2015
comment
Я пробовал reader.Cast<IEnumerable<dynamic>> и .Cast<dynamic>, но там написано: Cannot convert method group 'Cast' to non-delegate type 'dynamic'. Did you intend to invoke the method? что я там сделал не так? (Я просмотрел ваши источники, но они требовали, чтобы вы знали имя столбца, чего я не знаю) - person Travis Heeter; 27.07.2015
comment
@TravisHeeter Я не знаю, что вам не хватает, я думаю, вы что-то опечатаете. Попробуйте using (var reader = command.ExecuteReader()) { return reader.Cast<IDataRecord>().ToList(); } . См. Этот ответ для общего преобразования в объекты expando: stackoverflow.com/a/20223709/661933 - person nawfal; 27.07.2015
comment
Я пошел дальше и задал вопрос: stackoverflow.com/questions/31656938/ - person Travis Heeter; 27.07.2015

Если вам нужны только имена столбцов, вы можете сделать:

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

Но если вам нужна только одна строка, мне нравится мое дополнение AdoHelper. Это дополнение отлично подходит, если у вас есть однострочный запрос и вы не хотите иметь дело с таблицей данных в своем коде. Он возвращает нечувствительный к регистру словарь имен столбцов и значений.

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;
}
person Yakir Manor    schedule 29.08.2013
comment
throw ex; - наихудшая практика. - person asawyer; 08.03.2017
comment
это просто пример - person Yakir Manor; 09.03.2017
comment
Asawyer, вы должны хотя бы сказать почему. Я полагаю, вы скажете, что вам следует использовать throw; вместо этого, чтобы не потерять исходные детали следа ремня. - person Brent Rittenhouse; 28.03.2017

Используйте метод расширения:

    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;
    }
person Rob Sedgwick    schedule 07.10.2014

Для меня я бы написал такой метод расширения:

public static string[] GetFieldNames(this SqlDataReader reader)
{
     return Enumerable.Range(0, reader.FieldCount).Select(x => reader.GetName(x)).ToArray();
}
person Kinin Roza    schedule 05.01.2021

Я использую метод GetSchemaTable, который предоставляется через интерфейс IDataReader.

person keith    schedule 17.09.2012
comment
да, вот статья об этом: Получение информации о схеме из устройства хранения данных msdn.microsoft.com/en-us/library/haa3afyz (v = vs.110) .aspx - person Patrik Lindström; 08.03.2015

Вы конечно можете.


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

}

Источник: http://www.dotnetjunkies.ddj.com/Article/B82A22D1-8437-4C7A-B6AA-C6C9BE9DB8A6.dcik

person Jeremiah Peschka    schedule 25.03.2009

Это проще сделать в 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();
person Almett    schedule 12.04.2017

person    schedule
comment
Безумие, что нет перечислимого интерфейса, который позволяет выполнять итерацию по столбцам. - person JohnFx; 16.06.2011
comment
Немного короче: columns = Enumerable.Range(0, reader.FieldCount) .Select(reader.GetName).ToList(); - person Alex; 23.05.2013
comment
Это прекрасно работает. Я также обнаружил, что все имена моих столбцов были прописными, если я не использовал кавычки вокруг имени столбца. SELECT id AS "MyId" FROM table; - person styfle; 13.07.2013
comment
сэр, он возвращает все имена столбцов в нижнем регистре. Имена столбцов в таблице все в верхнем регистре, как OBJECTID, а читатель возвращает нижний регистр, как objectid. - person Muneem Habib; 17.11.2015
comment
можем ли мы получить тип столбца, такой как строка, int? - person Muneem Habib; 02.12.2015
comment
как этот enumerable.range (). select работает в vb.net? Любые идеи? - person swe; 16.01.2017
comment
его Dim columns () As String = Enumerable.Range (0, cTab.FieldCount) .Select (Function (n) cTab.GetName (n)). ToArray - person swe; 16.01.2017
comment
Если я правильно помню (что сомнительно), то, возвращаются ли имена столбцов в нижнем или верхнем регистре, зависит от используемой вами базы данных. PostgreSQL, который я использую большую часть времени, отображает их в нижнем регистре, а SQL Server - в верхнем регистре. Мы будем благодарны за любые исправления в этом заявлении. - person ROBERT RICHARDSON; 16.07.2018
comment
@ROBERTRICHARDSON Если не указано иное, SQL Server возвращает имена столбцов как есть. - person Tom Lint; 06.10.2020