2016-08-23 1 views
2

Я пытаюсь создать файл Excel через код C#, и сценарий заключается в том, что у меня есть хранимая процедура, которая возвращает 15000 записей, и я читаю данные через SqlDataAdapter и данные затем заполняется в DataTable, а затем я заполняю данные в файл excel, но через некоторое время приложение выдает ошибку ниже.Получение ошибки при создании Excel с помощью C#: переход в контекст COM 0x56b098

Ошибка:

Transition into COM context 0x56b098 for this RuntimeCallableWrapper failed with the following error: System call failed. (Exception from HRESULT: 0x80010100 (RPC_E_SYS_CALL_FAILED)). This is typically because the COM context 0x56b098 where this RuntimeCallableWrapper was created has been disconnected or it is busy doing something else. Releasing the interfaces from the current COM context (COM context 0x56af28). This may cause corruption or data loss. To avoid this problem, please ensure that all COM contexts/apartments/threads stay alive and are available for context transition, until the application is completely done with the RuntimeCallableWrappers that represents COM components that live inside them.

Ниже приведен код, я использую

public DataTable getData(string query,string year,string month) 
{ 
     SqlDataAdapter da = new SqlDataAdapter(); 
     DataTable dt = new DataTable(); 
     SqlCommand cmd = new SqlCommand(query,con); 
     cmd.Parameters.AddWithValue("@YR", year); 
     cmd.Parameters.AddWithValue("@MN", month); 
     cmd.CommandType = CommandType.StoredProcedure; 
     cmd.CommandTimeout = 0; 
     da.SelectCommand = cmd; 
     da.Fill(dt); 

     return dt; 
    } 

Основной метод

private void btn_MRRRetention_Click(object sender, EventArgs e) 
    { 
     // Working for creating MRR Retention Excel File 
     DataTable dt_Mrr; 
     string Yr, mn; 
     int tot_rows; 



     Yr = Cmb_Yr.SelectedItem.ToString(); 
     mn = Cmb_Mnth.SelectedItem.ToString(); 

     if (xlApp == null) 
     { 
      MessageBox.Show("Excel is not properly installed!"); 
      return; 
     } 

     excel.Workbook xlWorkBook; 
     excel.Worksheet xlWorkSheet; 
     object misValue = System.Reflection.Missing.Value; 

     xlWorkBook = xlApp.Workbooks.Add(misValue); 
     xlWorkSheet = (excel.Worksheet)xlWorkBook.Worksheets.get_Item(1); 

     // Data Reader Code start for collecting data from DB and pasting into Excel 
     pictureBox2.Visible = true; 
     dt_Mrr = func.getData("sp_MRR_Retention_APAC", Yr, mn); 
     //string text = "exec sp_Mrr_Retention" + "'" + Yr + "','" + mn + "'"; 
     tot_rows = dt_Mrr.Rows.Count; 
     int row = 2; 
     int i=0; 

     xlWorkSheet.Cells[1, 1] = "MONTH"; 
     xlWorkSheet.Cells[1, 2] = "Parent Name"; 
     xlWorkSheet.Cells[1, 3] = "Customer_Name"; 
     xlWorkSheet.Cells[1, 4] = "Customer_Account_No"; 
     xlWorkSheet.Cells[1, 5] = "Item_Category"; 
     xlWorkSheet.Cells[1, 6] = "Item_Description_Summary"; 
     xlWorkSheet.Cells[1, 7] = "Item_Number"; 
     xlWorkSheet.Cells[1, 8] = "Date_Range"; 
     xlWorkSheet.Cells[1, 9] = "Activity_Type"; 
     xlWorkSheet.Cells[1, 10] = "Line_Type"; 
     xlWorkSheet.Cells[1, 11] = "IBX_Code"; 
     xlWorkSheet.Cells[1, 12] = "IBX_Country"; 
     xlWorkSheet.Cells[1, 13] = "IBX_Region"; 
     xlWorkSheet.Cells[1, 14] = "Primary_Sales_Rep"; 
     xlWorkSheet.Cells[1, 15] = "MRC_Amount_USD_Budget_Rate"; 
     xlWorkSheet.Cells[1, 16] = "Entered_Currency_Code"; 
     xlWorkSheet.Cells[1, 17] = "MRC_Amount_LC"; 
     xlWorkSheet.Cells[1, 18] = "UCM ID"; 
     xlWorkSheet.Cells[1, 19] = "GAM_TAG"; 
     xlWorkSheet.Cells[1, 20] = "Client Services Manager"; 
     xlWorkSheet.Cells[1, 21] = "Sales Program Type"; 
     xlWorkSheet.Cells[1, 22] = "SFDC Account Id"; 
     xlWorkSheet.Cells[1, 23] = "Account Owner"; 

     //rs = func.getReader("sp_MRR_Retention '" + Yr + "','" + mn + "'"); 

     while (tot_rows>i) 
     { 
      xlWorkSheet.Cells[row, 1] = dt_Mrr.Rows[i]["MONTH"]; 
      xlWorkSheet.Cells[row, 2] = dt_Mrr.Rows[i]["Parent Name"]; 
      xlWorkSheet.Cells[row, 3] = dt_Mrr.Rows[i]["Customer_Name"]; 
      xlWorkSheet.Cells[row, 4] = dt_Mrr.Rows[i]["Customer_Account_No"]; 
      xlWorkSheet.Cells[row, 5] = dt_Mrr.Rows[i]["Item_Category"]; 
      xlWorkSheet.Cells[row, 6] = dt_Mrr.Rows[i]["Item_Description_Summary"]; 
      xlWorkSheet.Cells[row, 7] = dt_Mrr.Rows[i]["Item_Number"]; 
      xlWorkSheet.Cells[row, 8] = dt_Mrr.Rows[i]["Date_Range"]; 
      xlWorkSheet.Cells[row, 9] = dt_Mrr.Rows[i]["Activity_Type"]; 
      xlWorkSheet.Cells[row, 10] = dt_Mrr.Rows[i]["Line_Type"]; 
      xlWorkSheet.Cells[row, 11] = dt_Mrr.Rows[i]["IBX_Code"]; 
      xlWorkSheet.Cells[row, 12] = dt_Mrr.Rows[i]["IBX_Country"]; 
      xlWorkSheet.Cells[row, 13] = dt_Mrr.Rows[i]["IBX_Region"]; 
      xlWorkSheet.Cells[row, 14] = dt_Mrr.Rows[i]["Primary_Sales_Rep"]; 
      xlWorkSheet.Cells[row, 15] = dt_Mrr.Rows[i]["MRC_Amount_USD_Budget_Rate"]; 
      xlWorkSheet.Cells[row, 16] = dt_Mrr.Rows[i]["Entered_Currency_Code"]; 
      xlWorkSheet.Cells[row, 17] = dt_Mrr.Rows[i]["MRC_Amount_LC"]; 
      xlWorkSheet.Cells[row, 18] = dt_Mrr.Rows[i]["UCM ID"]; 
      xlWorkSheet.Cells[row, 19] = dt_Mrr.Rows[i]["GAM_TAG"]; 
      xlWorkSheet.Cells[row, 20] = dt_Mrr.Rows[i]["Client Services Manager"]; 
      xlWorkSheet.Cells[row, 21] = dt_Mrr.Rows[i]["Sales Program Type"]; 
      xlWorkSheet.Cells[row, 22] = dt_Mrr.Rows[i]["SFDC Account Id"]; 
      xlWorkSheet.Cells[row, 23] = dt_Mrr.Rows[i]["Account Owner"]; 

      row++; 
      i++; 

      //For Checking purpose! 
      //if (i == 1000) 
      //{ 
      // break; 
      //} 
     } 

     // Data Reader Code Ends Here 
     xlWorkBook.SaveAs("D:\\MRR_Retention_Auto.xls", excel.XlFileFormat.xlWorkbookNormal, misValue, misValue, misValue, misValue, excel.XlSaveAsAccessMode.xlExclusive, misValue, misValue, misValue, misValue, misValue); 
     xlWorkBook.Close(true, misValue, misValue); 
     xlApp.Quit(); 

     releaseObject(xlWorkSheet); 
     releaseObject(xlWorkBook); 
     releaseObject(xlApp); 

     pictureBox2.Visible = false; 

     MessageBox.Show("Excel file created , you can find the file D:\\MRR_Retention_Auto.xls"); 

    } 

мне нужна помощь по этой проблеме и с нетерпением жду этого.

+0

Это должно быть «Ячейки [строка, 1] .Value =' – Slai

+0

Предоставляет ли исключение номер строки, в которой происходит это исключение. Исключение COM может иметь много причин, но одна вещь, которую я бы рекомендовал вам попробовать, - это изменить цикл while на while (i faljbour

+0

@faljbour Нет, это не дает мне номер строки, и если я изменяю цикл while поэтому на первой итерации «i» уже меньше «tot_rows», и она не войдет в цикл. –

ответ

0

Мне кажется, что вы можете получить большую эффективность, полностью отбросив данные. Datatables отличные, но у них есть накладные расходы, и мне интересно, влияет ли накладные расходы на заполнение 15 000 строк в datatable, влияя на ваш COM-обмен.

Вот решение, позволяющее избежать ввода данных. Он предполагает, что хранимая процедура будет выгружать столбцы в том же порядке, который вы хотите увидеть в Excel.

Во-первых, ваш метод getData возвращают SqlCommand объект вместо DataTable:

public SqlCommand getData(string query, string year, string month) 
{ 
    SqlCommand cmd = new SqlCommand(query, con); 
    cmd.Parameters.AddWithValue("@YR", year); 
    cmd.Parameters.AddWithValue("@MN", month); 
    cmd.CommandType = CommandType.StoredProcedure; 
    cmd.CommandTimeout = 0; 

    return cmd; 
} 

здесь, ваши вызовы функций и вывод в Excel может просто выглядеть следующим образом:

SqlCommand cmd = func.getData("sp_MRR_Retention_APAC", Yr, mn); 

SqlDataReader reader = cmd.ExecuteReader(); 
for (int col = 0; col < reader.FieldCount; col++) 
    xlWorkSheet.Cells[col + 1, 1].Value2 = reader.GetName(col); 

while (reader.Read()) 
{ 
    for (int col = 0; col < reader.FieldCount; col++) 
     if (!reader.IsDBNull(col)) 
      xlWorkSheet.Cells[row, col + 1] = reader.GetValue(col); 
    row++; 
} 

reader.Close(); 

You может даже обернуть это одним способом для ввода данных Excel:

public void getData(string query, string year, string month, excel.Worksheet Ws) 
{ 
    SqlCommand cmd = new SqlCommand(query, con); 
    cmd.Parameters.AddWithValue("@YR", year); 
    cmd.Parameters.AddWithValue("@MN", month); 
    cmd.CommandType = CommandType.StoredProcedure; 
    cmd.CommandTimeout = 0; 

    int row = 1; 

    SqlDataReader reader = cmd.ExecuteReader(); 
    for (int col = 0; col < reader.FieldCount; col++) 
     Ws.Cells[col + 1, 1].Value2 = reader.GetName(col); 

    while (reader.Read()) 
    { 
     for (int col = 0; col < reader.FieldCount; col++) 
      if (!reader.IsDBNull(col)) 
       Ws.Cells[row, col + 1] = reader.GetValue(col); 
     row++; 
    } 

    reader.Close(); 
} 

Что бы упростить весь этот код в ваш основной метод:

func.getData("sp_MRR_Retention_APAC", Yr, mn, xlWorkSheet); 

Вот реальный кикер ... MS Query, который встроен в Excel, на самом деле делает все это для вас. Обычно вы используете ODBC, но с MS SQL Server вы можете напрямую обращаться к серверу без ODBC - перкуссии сожительства Microsoft-Microsoft. Честно говоря, я никогда не пробовал это с сохраненным proc, но с запросом он работал бы великолепно. У меня нет оснований сомневаться, что MS Query будет работать с процедурой.

Вызов MS Query в C# будет выглядеть примерно так:

excel.ListObject lo = sheet.ListObjects.AddEx(excel.XlListObjectSourceType.xlSrcQuery, 
    connectionString, true, Excel.XlYesNoGuess.xlGuess, range); 
lo.QueryTable.CommandText = queryText; 
lo.Refresh(); 

И вы найдете это очень быстро - я осмелюсь сказать, что это будет конкурировать все, что вы можете написать вручную.

Смежные вопросы