Bạn có thể lấy tên cột từ SqlDataReader không?


276

Sau khi kết nối với cơ sở dữ liệu, tôi có thể lấy tên của tất cả các cột được trả về trong mình SqlDataReaderkhông?

Câu trả lời:


460
var reader = cmd.ExecuteReader();

var columns = new List<string>();

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

hoặc là

var columns = Enumerable.Range(0, reader.FieldCount).Select(reader.GetName).ToList();

71
thật điên rồ khi không có giao diện vô số cho phép bạn lặp qua các cột.
JohnFx

61
Ngắn hơn một chút:columns = Enumerable.Range(0, reader.FieldCount) .Select(reader.GetName).ToList();
Alex

2
Điều này làm việc tuyệt vời. Tôi cũng phát hiện ra rằng tên cột của tôi đều là chữ hoa trừ khi tôi sử dụng dấu ngoặc kép quanh tên cột. SELECT id AS "MyId" FROM table;
styfle

thưa ngài trả lại tất cả các tên cột bằng chữ thường. Các tên cột trong bảng đều là chữ hoa như OBRIID và trình đọc đang trả về chữ thường như objectid
Muneem Habib

2
các cột Dim của nó () As String = Enumerable.Range (0, cTab.FieldCount) .Select (Function (n) cTab.GetName (n)). ToArray
swe

77

Có một GetNamehàm trên SqlDataReaderđó chấp nhận chỉ mục cột và trả về tên của cột.

Ngược lại, có một GetOrdinalcái lấy tên cột và trả về chỉ mục cột.


3
Hai lý do: thứ nhất, người đăng ban đầu chưa chọn câu trả lời và thứ hai, có những câu trả lời khác mô tả chi tiết hơn về 'giải pháp' của vấn đề, sau đó chỉ là sự tồn tại của chức năng. Cá nhân, tôi thích câu trả lời của Steven Lyons tốt nhất vì nó không chỉ nói về GetName mà còn đi vào FieldType và DataType.
Stephen Wrighton

1
GetOrdinalHoàn hảo. Tôi đã tìm kiếm GetName, nhưng giải pháp sạch hơn nhiều cho vấn đề của tôi với GetOrdinal.
tạm biệt

43

Bạn có thể lấy tên cột từ DataReader.

Đây là phần quan trọng:

  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

Đã được đề cập. Chỉ cần một câu trả lời 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();

Cái thứ hai sạch hơn và nhanh hơn nhiều. Ngay cả khi bạn lưu trữ GetSchemaTabletheo cách tiếp cận đầu tiên, việc truy vấn sẽ rất chậm.


Có cách nào để làm điều này với Giá trị không?
Travis Heeter

@TravisHeeter Tôi không hiểu bạn. Tìm tên cột từ các giá trị của cái gì?
nawfal

Ý tôi là chỉ là một cách đông để đưa các giá trị trong kết quả được đặt vào một danh sách, hoặc có lẽ là toàn bộ đối với một đối tượng <động> IEnumerable.
Travis Heeter

@TravisHeeter có thể làm được reader.Cast<IDataRecord>().ToList(). Tôi tin rằng bạn có thể sử dụng dynamictừ khóa ở đó thay vì IDataRecordnhưng không có lợi ích. DataTableđược thiết kế để dễ dàng tải một lần, do đó bạn cũng có thể sử dụng nhưng bạn sẽ mất lợi ích của việc tải theo yêu cầu (với trình đọc dữ liệu bạn có thể ngừng tải tại bất kỳ thời điểm nào), như thế var dt = new DataTable(); dt.Load(reader); return dt.AsEnumerable().ToList();. Có rất nhiều thư viện có thể tự động hóa việc này cho bạn, tìm chúng ở đây stackoverflow.com/questions/11988441 và ở đây stackoverflow.com/questions/1464883
nawfal

Tôi đã thử reader.Cast<IEnumerable<dynamic>>.Cast<dynamic>, nhưng nó nói, Cannot convert method group 'Cast' to non-delegate type 'dynamic'. Did you intend to invoke the method?tôi đã làm gì sai ở đó? (Tôi đã xem các nguồn của bạn, nhưng họ yêu cầu bạn phải biết tên cột mà tôi không biết)
Travis Heeter

6

Nếu bạn chỉ muốn tên cột, bạn có thể làm:

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

Nhưng nếu bạn chỉ cần một hàng, tôi thích phần bổ sung AdoHelper của tôi. Bổ sung này là tuyệt vời nếu bạn có một truy vấn dòng đơn và bạn không muốn xử lý bảng dữ liệu trong mã của mình. Nó trả về một từ điển không nhạy cảm của các tên và giá trị cột.

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;là một thực tế tồi tệ nhất.
asawyer

2
nó chỉ là một ví dụ
Yakir Manor

5
Asawyer, ít nhất bạn nên nói lý do tại sao. Tôi cho rằng bạn sẽ nói bạn nên sử dụng "ném;" thay vào đó để bạn không bị mất các chi tiết theo dõi strack ban đầu.
Brent Rittenhouse


3

Sử dụng phương pháp mở rộng:

    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

Bạn chắc chắn có thể.


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

}

Đây là bản gốc từ: http://www.dotnetjunkies.ddj.com/Article/B82A22D1-8437-4C7A-B6AA-C6C9BE9DB8A6.dcik


1

Nó dễ dàng hơn để đạt được nó trong 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();
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.