我正在尝试通过C#代码创建一个Excel文件,方案是我有一个存储过程,它返回15000条记录,我正在通过SqlDataAdapter
读取数据,然后数据填入{{1然后我将数据填充到excel文件中但是一段时间后应用程序抛出以下错误。
错误:
为此RuntimeCallableWrapper转换到COM上下文0x56b098失败,并显示以下错误:系统调用失败。 (来自HRESULT的异常:0x80010100(RPC_E_SYS_CALL_FAILED))。这通常是因为创建此RuntimeCallableWrapper的COM上下文0x56b098已断开连接或正忙于执行其他操作。从当前COM上下文释放接口(COM上下文0x56af28)。这可能会导致损坏或数据丢失。要避免此问题,请确保所有COM上下文/公寓/线程都保持活动状态并可用于上下文转换,直到应用程序完全使用表示其中的COM组件的RuntimeCallableWrappers完成。
以下是我正在使用的代码
DataTable
主要方法
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;
}
我需要帮助解决这个问题并期待它。
答案 0 :(得分:0)
在我看来,通过完全删除数据表可以获得很多效率。数据表很棒,但它们确实有开销,我想知道在数据表中填充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 Query,内置于Excel中,实际上为您完成了所有这些。通常使用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();
你会发现它非常快 - 我敢说它可以与你手工编写的东西相媲美。