2013-09-23 10 views
62

मैं सी # (एमएस वीएस -2008) में एक मूल बात कर रहा हूं और विशिष्ट कोड की तुलना में उचित डिज़ाइन के बारे में एक प्रश्न पूछता हूं।डेटा रीडर से डेटा तालिका पॉप्युलेट करें

मैं एक डाटाटेबल बना रहा हूं और फिर डेटाटेडर से डेटाटेबल लोड करने की कोशिश कर रहा हूं (जो एक एसक्यूएल संग्रहीत प्रक्रिया पर आधारित है)। मैं क्या सोच रहा हूं कि डेटाटेबल को लोड करने का सबसे प्रभावी तरीका कुछ वक्तव्य करना है, या यदि कोई बेहतर तरीका है।

मेरे लिए केवल एक ही दोष है कि मुझे उन क्षेत्रों में मैन्युअल रूप से टाइप करना होगा जिन्हें मैं अपने वक्तव्य वक्त में जोड़ना चाहता हूं, लेकिन मुझे यह भी स्वचालित करने के तरीके के बारे में पता नहीं है क्योंकि मैं सभी क्षेत्रों को नहीं चाहता एसपी सिर्फ लोगों का चयन करें, लेकिन यह मेरी आंखों में एक बड़ा सौदा नहीं है।

मैंने जो कुछ किया है, उसके नीचे कोड स्निपेट शामिल किए हैं, हालांकि मेरे लिए कोड स्वयं उल्लेखनीय नहीं है या यहां तक ​​कि मैं जो भी पूछ रहा हूं। मोरेसो मेरी पद्धति के बारे में सोच रहा है, अगर मेरी रणनीति गलत/अक्षम है तो मैं बाद में कोड सहायता के लिए पेस्टर करूंगा।

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

डुप्लिकेट प्रश्न के लिए तेज़ी से काम करता है: http://stackoverflow.com/questions/4089471/how-do-i-fill-a-datatable-using-datareader – vapcguy

उत्तर

179

आप Load() विधि है कि एक IDataReader स्वीकार करता है का उपयोग करते हुए एक डेटा पाठक से एक DataTable सीधे लोड कर सकते हैं स्वचालित रूप से यह परिवर्तित कर देंगे।

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

आप एक 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 संग्रहीत प्रक्रिया कमांड है।

+0

केवल समस्या यह है कि यदि आप कॉलम/मान को भरने के दौरान अपवाद का कारण बनता है, यह आपको कोई विवरण नहीं देता है, जैसे कि आप 'SqlDataReader' का उपयोग करके और फ़ील्ड के माध्यम से लूप का उपयोग करने में उन्हें पढ़ने में सक्षम हो सकते हैं। – vapcguy

15

कृपया नीचे दिए गए कोड को देखें। 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(); 
     } 

    } 
+0

डेटाटेडर को डेटाटेबल लोड करने का एक सीधा आगे विकल्प है, तो कोई इसका उपयोग क्यों करेगा? – Abbas

+0

@ सारथकुमार अच्छा काम .. मैं ऐसे कोड की तलाश कर रहा था – SimpleGuy

+0

@Abbas Coz, इनबिल्ट डेटा लोड बहुत धीमा है – SimpleGuy

9

जैसा सागी ने अपने उत्तर में डेटाटेबल कहा। लोड एक अच्छा समाधान है। यदि आप एक पाठक से एकाधिक टेबल लोड करने का प्रयास कर रहे हैं तो आपको 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); 
} 
2

मैं भी इस में देखा, और SqlDataReader.Load funcitons साथ SqlDataAdaptor.Fill विधि तुलना करने के बाद, मुझे लगता है कि SqlDataAdaptor पाया है।भरें विधि दो बार के रूप परिणाम सेट मैं

प्रयुक्त कोड का उपयोग कर के साथ तेजी से कहीं अधिक है:

[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 डेटा एडाप्टर 100 बार तालिका 10000 पंक्तियों को भरें: 11782 मिलीसेकंड
एसक्यूएल डेटा रीडर 100 गुना टेबल लोड स्पीड 10000 पंक्तियां: 26047 मिलीसेकंड
1000 पंक्तियां:
SQL डेटा एडाप्टर 100 बार तालिका भरने गति 1000 पंक्तियाँ: 984 मिलीसेकेंड
SQL डेटा रीडर 100 बार तालिका लोड गति 1000 पंक्तियाँ: 2031 मिलीसेकेंड
100 पंक्तियां:
SQL डेटा एडाप्टर 100 बार तालिका भरने गति अधिकतम 100 पंक्तियां: 125 मिलीसेकेंड
SQL डेटा रीडर 100 बार तालिका लोड गति अधिकतम 100 पंक्तियां: 235 मिलीसेकेंड
10 पंक्तियों:
SQL डेटा एडाप्टर 100 बार तालिका भरने की गति 10 पंक्तियों: 32 मिलीसेकंड
SQL डेटा रीडर 100 बार तालिका लोड गति 10 पंक्तियों: 93 मिलीसेकंड

प्रदर्शन समस्याओं के लिए, SqlDataAdaptor.Fill विधि का उपयोग करना अधिक कुशल है। तो जब तक आप पैर के उपयोग में खुद को शूट नहीं करना चाहते हैं। यह छोटे और बड़े डेटा सेट

संबंधित मुद्दे