从数据读取器填充数据表

我正在做一个基本的东西在C#(MS VS2008),并有一个比正确的devise比特定的代码更多的问题。

我正在创build一个数据表,然后尝试从一个datareader(这是基于SQL存储过程)加载数据表。 我想知道的是,加载数据表最有效的方法是做一个while语句,或者是否有更好的方法。

对我来说,唯一的缺点是我必须手动input我想添加在我的while语句中的字段,但是我也不知道如何自动执行,因为我不希望SP中的所有字段都只是select字段,但这在我眼里并不是什么大事。

我将代码片段包含在我所做的全部内容之下,但对我来说,代码本身并不显着,甚至不是我所问的。 更多的是对我的方法感到疑惑,如果我的策略是错误的/效率低下的,我会在后面为代码提供帮助。

var dtWriteoffUpload = new DataTable(); dtWriteoffUpload.Columns.Add("Unit"); dtWriteoffUpload.Columns.Add("Year"); dtWriteoffUpload.Columns.Add("Period"); dtWriteoffUpload.Columns.Add("Acct"); dtWriteoffUpload.Columns.Add("Descr"); dtWriteoffUpload.Columns.Add("DEFERRAL_TYPE"); dtWriteoffUpload.Columns.Add("NDC_Indicator"); dtWriteoffUpload.Columns.Add("Mgmt Cd"); dtWriteoffUpload.Columns.Add("Prod"); dtWriteoffUpload.Columns.Add("Node"); dtWriteoffUpload.Columns.Add("Curve_Family"); dtWriteoffUpload.Columns.Add("Sum Amount"); dtWriteoffUpload.Columns.Add("Base Curr"); dtWriteoffUpload.Columns.Add("Ledger"); cmd = util.SqlConn.CreateCommand(); cmd.CommandTimeout = 1000; cmd.CommandType = CommandType.StoredProcedure; cmd.CommandText = "proc_writeoff_data_details"; cmd.Parameters.Add("@whoAmI", SqlDbType.VarChar).Value = WindowsIdentity.GetCurrent().Name; cmd.Parameters.Add("@parmEndDateKey", SqlDbType.VarChar).Value = myMostRecentActualDate; cmd.Parameters.Add("@countrykeys", SqlDbType.VarChar).Value = myCountryKey; cmd.Parameters.Add("@nodekeys", SqlDbType.VarChar).Value = "1,2"; break; dr = cmd.ExecuteReader(); while (dr.Read()) { dtWriteoffUpload.Rows.Add(dr["country name"].ToString(), dr["country key"].ToString()); } 

您可以使用接受IDataReaderLoad()方法直接从数据读取器加载DataTable

 var dataReader = cmd.ExecuteReader(); var dataTable = new DataTable(); dataTable.Load(dataReader); 

请检查下面的代码。 自动将它转换为DataTable

 private void ConvertDataReaderToTableManually() { SqlConnection conn = null; try { string connString = ConfigurationManager.ConnectionStrings["NorthwindConn"].ConnectionString; conn = new SqlConnection(connString); string query = "SELECT * FROM Customers"; SqlCommand cmd = new SqlCommand(query, conn); conn.Open(); SqlDataReader dr = cmd.ExecuteReader(CommandBehavior.CloseConnection); DataTable dtSchema = dr.GetSchemaTable(); DataTable dt = new DataTable(); // You can also use an ArrayList instead of List<> List<DataColumn> listCols = new List<DataColumn>(); if (dtSchema != null) { foreach (DataRow drow in dtSchema.Rows) { string columnName = System.Convert.ToString(drow["ColumnName"]); DataColumn column = new DataColumn(columnName, (Type)(drow["DataType"])); column.Unique = (bool)drow["IsUnique"]; column.AllowDBNull = (bool)drow["AllowDBNull"]; column.AutoIncrement = (bool)drow["IsAutoIncrement"]; listCols.Add(column); dt.Columns.Add(column); } } // Read rows from DataReader and populate the DataTable while (dr.Read()) { DataRow dataRow = dt.NewRow(); for (int i = 0; i < listCols.Count; i++) { dataRow[((DataColumn)listCols[i])] = dr[i]; } dt.Rows.Add(dataRow); } GridView2.DataSource = dt; GridView2.DataBind(); } catch (SqlException ex) { // handle error } catch (Exception ex) { // handle error } finally { conn.Close(); } } 

如果您正在尝试加载DataTable ,请改用SqlDataAdapter

 DataTable dt = new DataTable(); using (SqlConnection c = new SqlConnection(cString)) using (SqlDataAdapter sda = new SqlDataAdapter(sql, c)) { sda.SelectCommand.CommandType = CommandType.StoredProcedure; sda.SelectCommand.Parameters.AddWithValue("@parm1", val1); ... sda.Fill(dt); } 

你甚至不需要定义列。 只需创buildDataTableFill它。

在这里, cString是你的连接string, sql是存储过程命令。

正如Sagi在他们的回答DataTable.Load中所说的是一个很好的解决scheme。 如果您试图从一个阅读器加载多个表,则不需要调用DataReader.NextResult。 DataTable.Load方法也将读者推进到下一个结果集(如果有的话)。

 // Read every result set in the data reader. while (!reader.IsClosed) { DataTable dt = new DataTable(); // DataTable.Load automatically advances the reader to the next result set dt.Load(reader); items.Add(dt); } 

我也考虑到了这一点,在比较SqlDataAdaptor.Fill方法和SqlDataReader.Load函数之后,我发现SqlDataAdaptor.Fill方法的速度是我用过的结果集的两倍多

使用的代码:

  [TestMethod] public void SQLCommandVsAddaptor() { long adaptorFillLargeTableTime, readerLoadLargeTableTime, adaptorFillMediumTableTime, readerLoadMediumTableTime, adaptorFillSmallTableTime, readerLoadSmallTableTime, adaptorFillTinyTableTime, readerLoadTinyTableTime; string LargeTableToFill = "select top 10000 * from FooBar"; string MediumTableToFill = "select top 1000 * from FooBar"; string SmallTableToFill = "select top 100 * from FooBar"; string TinyTableToFill = "select top 10 * from FooBar"; using (SqlConnection sconn = new SqlConnection("Data Source=.;initial catalog=Foo;persist security info=True; user id=bar;password=foobar;")) { // large data set measurements adaptorFillLargeTableTime = MeasureExecutionTimeMethod(sconn, LargeTableToFill, ExecuteDataAdapterFillStep); readerLoadLargeTableTime = MeasureExecutionTimeMethod(sconn, LargeTableToFill, ExecuteSqlReaderLoadStep); // medium data set measurements adaptorFillMediumTableTime = MeasureExecutionTimeMethod(sconn, MediumTableToFill, ExecuteDataAdapterFillStep); readerLoadMediumTableTime = MeasureExecutionTimeMethod(sconn, MediumTableToFill, ExecuteSqlReaderLoadStep); // small data set measurements adaptorFillSmallTableTime = MeasureExecutionTimeMethod(sconn, SmallTableToFill, ExecuteDataAdapterFillStep); readerLoadSmallTableTime = MeasureExecutionTimeMethod(sconn, SmallTableToFill, ExecuteSqlReaderLoadStep); // tiny data set measurements adaptorFillTinyTableTime = MeasureExecutionTimeMethod(sconn, TinyTableToFill, ExecuteDataAdapterFillStep); readerLoadTinyTableTime = MeasureExecutionTimeMethod(sconn, TinyTableToFill, ExecuteSqlReaderLoadStep); } using (StreamWriter writer = new StreamWriter("result_sql_compare.txt")) { writer.WriteLine("10000 rows"); writer.WriteLine("Sql Data Adapter 100 times table fill speed 10000 rows: {0} milliseconds", adaptorFillLargeTableTime); writer.WriteLine("Sql Data Reader 100 times table load speed 10000 rows: {0} milliseconds", readerLoadLargeTableTime); writer.WriteLine("1000 rows"); writer.WriteLine("Sql Data Adapter 100 times table fill speed 1000 rows: {0} milliseconds", adaptorFillMediumTableTime); writer.WriteLine("Sql Data Reader 100 times table load speed 1000 rows: {0} milliseconds", readerLoadMediumTableTime); writer.WriteLine("100 rows"); writer.WriteLine("Sql Data Adapter 100 times table fill speed 100 rows: {0} milliseconds", adaptorFillSmallTableTime); writer.WriteLine("Sql Data Reader 100 times table load speed 100 rows: {0} milliseconds", readerLoadSmallTableTime); writer.WriteLine("10 rows"); writer.WriteLine("Sql Data Adapter 100 times table fill speed 10 rows: {0} milliseconds", adaptorFillTinyTableTime); writer.WriteLine("Sql Data Reader 100 times table load speed 10 rows: {0} milliseconds", readerLoadTinyTableTime); } Process.Start("result_sql_compare.txt"); } private long MeasureExecutionTimeMethod(SqlConnection conn, string query, Action<SqlConnection, string> Method) { long time; // know C# // execute single read step outside measurement time, to warm up cache or whatever Method(conn, query); // start timing time = Environment.TickCount; for (int i = 0; i < 100; i++) { Method(conn, query); } // return time in milliseconds return Environment.TickCount - time; } private void ExecuteDataAdapterFillStep(SqlConnection conn, string query) { DataTable tab = new DataTable(); conn.Open(); using (SqlDataAdapter comm = new SqlDataAdapter(query, conn)) { // adaptor fill table function comm.Fill(tab); } conn.Close(); } private void ExecuteSqlReaderLoadStep(SqlConnection conn, string query) { DataTable tab = new DataTable(); conn.Open(); using (SqlCommand comm = new SqlCommand(query, conn)) { using (SqlDataReader reader = comm.ExecuteReader()) { // IDataReader Load function tab.Load(reader); } } conn.Close(); } 

结果:

10000行:
Sql Data Adapter 100次表填充速度10000行:11782毫秒
Sql数据读取器100次表加载速度10000行:26047毫秒
1000行:
Sql Data Adapter 100倍表填充速度1000行:984毫秒
Sql Data Reader 100倍表加载速度1000行:2031毫秒
100行:
Sql Data Adapter 100倍表填充速度100行:125毫秒
Sql Data Reader 100倍表加载速度100行:235毫秒
10行:
Sql Data Adapter 100倍表填充速度10行:32毫秒
Sql Data Reader 100倍表加载速度10行:93毫秒

对于性能问题,使用SqlDataAdaptor.Fill方法效率更高。 所以除非你想用自己的脚拍自己的脚 它对于小型和大型数据集运行速度更快