c# - 通过 C# : Transition into COM context 0x56b098 创建 Excel 时出错

标签 c# excel sqldataadapter

我正在尝试通过 C# 代码创建一个 Excel 文件,场景是我有一个返回 15000 条记录的存储过程,我正在通过 SqlDataAdapter 读取数据,然后将数据填充到DataTable 然后我将数据填充到 excel 文件中,但过了一会儿应用程序抛出以下错误。

错误:

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

    }

在这个问题上我需要帮助并期待它。

最佳答案

在我看来,完全删除数据表可能会提高效率。数据表很棒,但它们确实有开销,我想知道在数据表中填充 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);

这才是真正的关键……内置于 Excel 中的 MS Query 实际上会为您完成所有这些工作。通常您使用 ODBC,但是对于 MS SQL Server,您可以在没有 ODBC 的情况下直接访问服务器——这是 Microsoft 与 Microsoft 同居的一个好处。老实说,我从来没有用存储过程尝试过它,但是用查询它会很好地工作。我没有理由怀疑 MS Query 会在过程中运行。

C# 中的 MS Query 调用看起来像这样:

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

而且您会发现它的速度非常快——我敢说它可以与您手写的任何东西相媲美。

关于c# - 通过 C# : Transition into COM context 0x56b098 创建 Excel 时出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39111166/

相关文章:

java - 如何使用 Java 打开、保存和关闭 Excel 启用宏的工作表文件?

c# - 如何在 C# 中从 BindingSource 获取值

c# - 尝试将 SqlDataAdapter 中的 SqlCommand 作为参数传递

c# - 免费的 C# XML Diff 库或类

excel - 如何在多行/列 Excel 电子表格中查找值的位置?

c# - 自定义工作流事件中的依赖项注入(inject)

vba - 如何获取单元格在某个范围内的位置?

c# 在 SqlDataAdapter 中使用 Parameters.AddWithValue

c# - 如何通过单击事件隐藏或显示图像

c# - 如何从 excel 单元格中获取完整值,而不是显示的(四舍五入的)值?