你能从SqlDataReader中获取列名吗?

322

连接到数据库后,我能否在SqlDataReader中获取所有返回列的名称?

11个回答

531
var reader = cmd.ExecuteReader();

var columns = new List<string>();

for(int i=0;i<reader.FieldCount;i++)
{
   columns.Add(reader.GetName(i));
}
或者
var columns = Enumerable.Range(0, reader.FieldCount).Select(reader.GetName).ToList();

81
没有可枚举接口让你遍历列,这太不可思议了。 - JohnFx
67
稍微简短一些:columns = reader.GetSchemaTable().Rows.Cast<DataRow>().Select(row => row["ColumnName"].ToString()).ToList(); - Oleks
2
这个很好用。我还发现,除非我在列名周围使用引号,否则它们都是大写的。SELECT id AS "MyId" FROM table; - styfle
2
它的Dim columns() As String = Enumerable.Range(0, cTab.FieldCount).Select(Function(n) cTab.GetName(n)).ToArray - swe
1
除非另有指定,否则SQL Server返回列名不变。 - Tom Lint
显示剩余3条评论

87

SqlDataReader对象上有一个GetName函数,它接受列索引并返回列的名称。

相反地,还有一个GetOrdinal函数,它接受列名并返回列索引。


3
有两个原因:首先,原帖作者尚未选择答案;其次,其他答案描述了问题的“解决方案”的更多详细信息,而不仅仅是说明功能是否存在。就我个人而言,我认为Steven Lyons的答案最好,因为它不仅讨论了GetName,还涉及FieldType和DataType。 - Stephen Wrighton
2
"GetOrdinal" 很完美。我本来在寻找 "GetName",但是 "GetOrdinal" 对于我的问题提供了更加简洁的解决方案。 - goodeye

61

您可以从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
  }

20

已经提到过了。这是一篇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,查询速度也会非常慢。


有没有使用Values的方法可以实现这个? - Travis Heeter
@TravisHeeter 我不明白你的意思。从哪些值中查找列名? - nawfal
@TravisHeeter 是的,可以使用 reader.Cast<IDataRecord>().ToList()。我相信你可以使用 dynamic 关键字代替 IDataRecord,但没有任何好处。DataTable 的设计是为了简化一次性加载,所以你也可以使用它,但你会失去按需加载的好处(使用数据读取器,你可以在任何时候停止加载),例如 var dt = new DataTable(); dt.Load(reader); return dt.AsEnumerable().ToList();。有许多库可以自动化这个过程,你可以在这里找到它们 http://stackoverflow.com/questions/11988441 和 https://dev59.com/UnM_5IYBdhLWcg3wPAjT。 - nawfal
我尝试过 reader.Cast<IEnumerable<dynamic>>.Cast<dynamic>,但出现了 无法将方法组“Cast”转换为非委托类型“dynamic”。您是否打算调用该方法? 的错误提示。我哪里做错了?(我查看了您的资源,但它们要求您知道列名称,而我不知道) - Travis Heeter
我已经开始了一个问题:https://dev59.com/MlwZ5IYBdhLWcg3wQ-fl - Travis Heeter
显示剩余2条评论

7
如果您只需要列名,可以执行以下操作:
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;
}

1
抛出异常(ex)是一种最糟糕的做法。 - asawyer
2
这只是一个例子。 - Yakir Manor
7
Asawyer,你至少应该说出原因。我猜你会建议使用 "throw;" 代替当前代码,这样可以避免丢失原始的堆栈跟踪信息。 - Brent Rittenhouse

5

使用扩展方法:

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

5

对我而言,我会编写如下的扩展方法:

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

3
我使用GetSchemaTable方法,该方法通过IDataReader接口公开。

是的,这里有一篇关于从数据读取器获取模式信息的文章:https://msdn.microsoft.com/zh-cn/library/haa3afyz(v=vs.110).aspx - Patrik Lindström

2
当然可以。

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

本文将介绍如何使用DataReader和DataSet获取数据库表中的列名。


2

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接