SSIS使用脚本任务导出到Excel

时间:2016-06-21 09:34:50

标签: c# excel ssis

我尝试使用脚本任务将数据导出到Excel,因为我生成的某些报告只包含太多列以继续使用模板文件。

关于使用模板最烦人的部分是:如果像列标题这样简单的内容发生变化,元数据就会变得紧张,迫使我重新创建我的DataFlow。因为我使用OLE DB源,我需要使用数据转换任务在unicode和非unicode字符集之间进行转换,然后将我的Excel目标重新映射到"复制字段x"为了使Excel文档正确创建。 这需要太长时间,我需要一种新的方法。

我在使用Excel = Microsoft.Office.Interop.Excel的脚本任务中使用以下方法:

private void ExportToExcel(DataTable dataTable, string excelFilePath = null)
    {

        Excel.Application excelApp = new Excel.Application();
        Excel.Worksheet workSheet = null;

        try
        {
            if (dataTable == null || dataTable.Columns.Count == 0)
                throw new System.Exception("Null or empty input table!" + Environment.NewLine);

            excelApp.Workbooks.Add();

            workSheet = excelApp.ActiveSheet;

            for (int i = 0; i < dataTable.Columns.Count; i++)
            {
                workSheet.Cells[1, (i + 1)] = dataTable.Columns[i].ColumnName;
            }

            foreach (DataTable dt in dataSet.Tables)
            {

                // Copy the DataTable to an object array
                object[,] rawData = new object[dt.Rows.Count + 1, dt.Columns.Count];

                // Copy the column names to the first row of the object array
                for (int col = 0; col < dt.Columns.Count; col++)
                {
                    rawData[0, col] = dt.Columns[col].ColumnName;
                }

                // Copy the values to the object array
                for (int col = 0; col < dt.Columns.Count; col++)
                {
                    for (int row = 0; row < dt.Rows.Count; row++)
                    {
                        rawData[row + 1, col] = dt.Rows[row].ItemArray[col];
                    }
                }

                // Calculate the final column letter
                string finalColLetter = string.Empty;
                string colCharset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
                int colCharsetLen = colCharset.Length;

                if (dt.Columns.Count > colCharsetLen)
                {
                    finalColLetter = colCharset.Substring((dt.Columns.Count - 1) / colCharsetLen - 1, 1);
                }

                finalColLetter += colCharset.Substring((dt.Columns.Count - 1) % colCharsetLen, 1);

                workSheet.Name = dt.TableName;

                // Fast data export to Excel
                string excelRange = string.Format("A1:{0}{1}", finalColLetter, dt.Rows.Count + 1);


                //The code crashes here (ONLY in SSIS):
                workSheet.get_Range(excelRange, Type.Missing).Value2 = rawData;

                // Mark the first row as BOLD
                ((Excel.Range)workSheet.Rows[1, Type.Missing]).Font.Bold = true;
            }

            List<int> lstColumnsToSum = new List<int>() { 9 };
            Dictionary<int, string> dictColSumName = new Dictionary<int, string>() { { 9, "" } };
            Dictionary<int, decimal> dictColumnSummation = new Dictionary<int, decimal>() { { 9, 0 } };

            // rows
            for (int i = 0; i < dataTable.Rows.Count; i++)
            {
                for (int j = 1; j <= dataTable.Columns.Count; j++)
                {
                    workSheet.Cells[(i + 2), (j)] = dataTable.Rows[i][j - 1];
                    if (lstColumnsToSum.Exists(x => (x == j)))
                    {
                        decimal val = 0;
                        if (decimal.TryParse(dataTable.Rows[i][j - 1].ToString(), out val))
                        {
                            dictColumnSummation[j] += val;
                        }
                    }
                }
            }

            //Footer
            int footerRowIdx = 2 + dataTable.Rows.Count;

            foreach (var summablecolumn in dictColSumName)
            {
                workSheet.Cells[footerRowIdx, summablecolumn.Key] = String.Format("{0}", dictColumnSummation[summablecolumn.Key]);
            }

            // check fielpath
            if (excelFilePath != null && excelFilePath != "")
            {
                try
                {
                    if (File.Exists(excelFilePath))
                        File.Delete(excelFilePath);

                    workSheet.Activate();
                    workSheet.Application.ActiveWindow.SplitRow = 1;
                    workSheet.Application.ActiveWindow.FreezePanes = true;

                    int row = 1;
                    int column = 1;

                    foreach (var item in dataTable.Columns)
                    {
                        Excel.Range range = workSheet.Cells[row, column] as Excel.Range;
                        range.NumberFormat = "@";
                        range.EntireColumn.AutoFit();
                        range.Interior.Color = System.Drawing.ColorTranslator.ToOle(System.Drawing.Color.LightGray);
                        column++;
                    }

                    Excel.Range InternalCalculatedAmount = workSheet.Cells[1, 9] as Excel.Range;
                    InternalCalculatedAmount.EntireColumn.NumberFormat = "#0.00";
                    InternalCalculatedAmount.Columns.AutoFit();

                    workSheet.SaveAs(excelFilePath);
                }
                catch (System.Exception ex)
                {
                    throw new System.Exception("Excel file could not be saved! Check filepath." + Environment.NewLine + ex.Message);
                }
            }
            else    // no filepath is given
            {
                excelApp.Visible = true;
            }
        }
        catch (System.Exception ex)
        {
            throw new System.Exception("ex.Message + Environment.NewLine, ex.InnerException);
        }
    }

在尝试执行以下代码时,抛出的异常是System.OutOfMemoryException:

workSheet.get_Range(excelRange, Type.Missing).Value2 = rawData;

我最大的挫折是这种方法在普通的C#应用​​程序中100%工作。

DataTable包含大约435000行。我知道它有相当多的数据,但我使用这种方法,当然是经过修改,在我的其他应用程序中的多个Excel工作表之间拆分数据,而DataSet包含大约1.1m的行。因此,我最大的DataSet中不到一半应该是一个步入式公园...

任何关于此事的光明都会令人惊叹!

0 个答案:

没有答案