Заполнить таблицу данных из устройства чтения данных
Я делаю основную вещь в C# (MS VS2008) и у меня есть вопрос больше о правильном дизайне, чем о конкретном коде.
Я создаю datatable, а затем пытаюсь загрузить datatable из datareader (который основан на хранимой процедуре SQL). Что мне интересно, является ли наиболее эффективный способ, чтобы загрузить объект DataTable, чтобы сделать в то время как заявление, или если есть способ лучше.
для меня Единственным недостатком является то, что мне нужно вручную ввести поля, которые я хочу добавить в свой в то время как заявление, но я также не знаю способа автоматизировать это в любом случае, так как я не хочу, чтобы все поля из SP просто выбирали те, но это не так уж и много в моих глазах.
Я включил фрагменты кода ниже всей совокупности того, что я делаю, хотя для меня сам код не является замечательным или даже то, о чем я спрашиваю. Более того, задаваясь вопросом о моей методологии, я буду приставать к помощи кода позже, если моя стратегия неверна/неэффективна.
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());
}
5 ответов:
скачать
DataTable
непосредственно из устройства чтения данных с помощьюLoad()
метод, который принимаетIDataReader
.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(); } }
если вы пытаетесь загрузить a
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); }
вам даже не нужно определять столбцы. Просто создайте
DataTable
иFill
его.здесь
cString
- это строка подключения иsql
- это команда хранимой процедуры.
Как саги заявил в своем ответе DataTable.Нагрузка-это хорошее решение. Если вы пытаетесь загрузить несколько таблиц из одного устройства чтения, вам не нужно вызывать 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); }
Я тоже посмотрел на это, и после сравнения SqlDataAdapter.Заполните метод с помощью SqlDataReader.Загрузите функции, я обнаружил, что SqlDataAdapter.Метод заполнения более чем в два раза быстрее с результирующими наборами, которые я использую
использовать код:
[TestMethod] public void SQLCommandVsAddaptor() { long AdapterFillLargeTableTime, readerLoadLargeTableTime, AdapterFillMediumTableTime, readerLoadMediumTableTime, AdapterFillSmallTableTime, readerLoadSmallTableTime, AdapterFillTinyTableTime, 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 AdapterFillLargeTableTime = MeasureExecutionTimeMethod(sconn, LargeTableToFill, ExecuteDataAdapterFillStep); readerLoadLargeTableTime = MeasureExecutionTimeMethod(sconn, LargeTableToFill, ExecuteSqlReaderLoadStep); // medium data set measurements AdapterFillMediumTableTime = MeasureExecutionTimeMethod(sconn, MediumTableToFill, ExecuteDataAdapterFillStep); readerLoadMediumTableTime = MeasureExecutionTimeMethod(sconn, MediumTableToFill, ExecuteSqlReaderLoadStep); // small data set measurements AdapterFillSmallTableTime = MeasureExecutionTimeMethod(sconn, SmallTableToFill, ExecuteDataAdapterFillStep); readerLoadSmallTableTime = MeasureExecutionTimeMethod(sconn, SmallTableToFill, ExecuteSqlReaderLoadStep); // tiny data set measurements AdapterFillTinyTableTime = 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", AdapterFillLargeTableTime); 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", AdapterFillMediumTableTime); 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", AdapterFillSmallTableTime); 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", AdapterFillTinyTableTime); 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)) { // Adapter 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 rows: Sql Data Adapter 100 times table fill speed 10000 rows: 11782 milliseconds Sql Data Reader 100 times table load speed 10000 rows: 26047 milliseconds 1000 rows: Sql Data Adapter 100 times table fill speed 1000 rows: 984 milliseconds Sql Data Reader 100 times table load speed 1000 rows: 2031 milliseconds 100 rows: Sql Data Adapter 100 times table fill speed 100 rows: 125 milliseconds Sql Data Reader 100 times table load speed 100 rows: 235 milliseconds 10 rows: Sql Data Adapter 100 times table fill speed 10 rows: 32 milliseconds Sql Data Reader 100 times table load speed 10 rows: 93 milliseconds
для проблем с производительностью, используя SqlDataAdapter.Способ заполнения является гораздо более эффективным. Так что, если вы не хотите стрелять себе в ногу, используйте это. Он работает быстрее для малых и большие наборы данных.