2016-08-23 33 views
2

我想通过C#代码创建一个Excel文件,并且场景是我有一个存储过程,它返回15000条记录,我通过SqlDataAdapter和数据读取数据然后在DataTable中填充,然后我将数据填充到excel文件中,但过了一段时间后,应用程序抛出错误。通过C#获取创建Excel的错误:转换到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

它应该是'Cells [row,1] .Value =' – Slai

+0

这个异常是否会给出发生此异常的行号? COM异常可以有很多原因,但我建议你尝试的一件事是改变你的while循环为“while(i faljbour

+0

@faljbour不,它不给我的行号,如果我改变while循环所以在第一次迭代中,“我”已经小于“tot_rows”,并且它不会进入循环。 –

回答

0

在我看来,通过完全删除数据表,您可能会获得很多效率。 Datatables非常棒,但它们确实有开销,我不知道在数据表中填充15,000行的开销是否会影响您的COM通信。

这是避免数据表的解决方案。它的前提是存储过程将按照您希望在Excel中查看它们的顺序转储列。

首先,有你getData方法返回一个SqlCommand对象,而不是一个数据表:

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

你甚至可以用一种方法来包装,以执行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查询,这是内置到Excel中,实际上做这一切为您服务。通常情况下,你使用的是ODBC,但是使用MS SQL Server,你可以直接在没有ODBC的情况下直接访问服务器 - 微软与微软的同居。说实话,我从来没有用存储过程来试用它,但用查询它会出色地工作。我没有理由怀疑MS Query将使用一个过程来运行。

C#中的MS查询调用看起来是这样的:

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

而且你会发现它非常快 - 我敢说这将对手任何你可以手工编写。