将行插入 Excel 时提高 OpenXML 性能
Improve OpenXML performance when inserting rows into Excel
我使用 OpenXML v 2.8.1.0 为网站创建 excel 报告。电子表格有 22 列。呈现 15,000 行需要 30 秒,但这对于网页来说太长了。我可以更有效地做到这一点吗?
下面是代码片段(省略了与问题无关的部分)。怀疑我在循环遍历每个单元格以设置其单元格引用,然后还设置每一行的 rowIndex 时效率低下。
我在打开要填充的电子表格的地方遗漏了代码 - 它包含 headers 和示例详细信息行,其中包含我想要的所有格式,但所有值都是空白。
在代码中,我克隆该行,为每个单元格设置值和单元格引用,为该行设置 rowIndex,插入该行,然后从数据库中获取下一行数据并重复。
或者每秒 500 行的速度与 OpenXML 的速度差不多吗?
谢谢。
public class MyReport
{
public byte[] Get(List<dbRow> dbRows)
{
// dbRows is the result of "Select col0, col1, ... col21 from dbTable"
// first 6 rows are the report headers
// row 7 is the blank detail row.
Row templateDetailRow = sheetData.Elements<Row>().Where(r => r.RowIndex == 7).First();
// start inserting data rows at row number 8
uint currentRowPointer = sheetData.Elements<Row>().LastOrDefault().RowIndex + 1; // start adding rows after the current last row
Row currentBottomRow = sheetData.Elements<Row>().LastOrDefault(); // initialize to last row before we start adding rows
foreach (dbRow r in dbRows)
{
Row newRow = (Row)templateDetailRow.Clone();
List<Cell> cells = newRow.Elements<Cell>().OrderBy(c => c.CellReference.Value).ToList();
SetCellsInRow(cells, r, currentRowPointer);
newRow.RowIndex = currentRowPointer;
InsertRow(sheetData, newRow);
currentRowPointer++;
}
}
private void SetCellsInRow(List<Cell> cells, dbRow source, uint rowIndex)
{
SetCell(cells[0], source.string0, rowIndex);
SetCell(cells[1], source.int1, rowIndex);
SetCell(cells[2], source.string2, rowIndex);
SetCell(cells[3], source.string3, rowIndex);
SetCell(cells[4], source.string4, rowIndex);
SetCell(cells[5], String.Format("{0:MM/dd/yyyy}", source.date5), rowIndex);
SetCell(cells[6], source.string6, rowIndex);
SetCell(cells[7], source.int7, rowIndex);
SetCell(cells[8], source.string8, rowIndex);
SetCell(cells[9], source.string9, rowIndex);
SetCell(cells[10], source.date10.ToString("MM/dd/yyyy"), rowIndex);
SetCell(cells[11], String.Format("{0:MM/dd/yyyy}", source.date11), rowIndex);
SetCell(cells[12], String.Format("{0:MM/dd/yyyy}", source.date12), rowIndex);
SetCell(cells[13], source.string13, rowIndex);
SetCell(cells[14], String.Format("{0:MM/dd/yyyy}", source.date14), rowIndex);
SetCell(cells[15], source.int15 ?? 0, rowIndex);
SetCell(cells[16], String.Format("{0:MM/dd/yyyy}", source.date16), rowIndex);
SetCell(cells[17], source.string17, rowIndex);
SetCell(cells[18], source.string18, rowIndex);
SetCell(cells[19], source.int19, rowIndex);
SetCell(cells[20], source.string20, rowIndex);
SetCell(cells[21], source.string21, rowIndex);
}
private void SetCell(Cell theCell, string val, uint rowIndex)
{ // a NON-SHARED string is going in to the cell
theCell.CellValue = new CellValue(val);
theCell.DataType = new EnumValue<CellValues>(CellValues.String);
theCell.CellReference = Regex.Replace(theCell.CellReference, @"\d+", rowIndex.ToString());
}
private void SetCell(Cell theCell, int val, uint rowIndex)
{ // an int is going in to the cell
theCell.CellValue = new CellValue(val.ToString());
theCell.DataType = new EnumValue<CellValues>(CellValues.Number);
theCell.CellReference = Regex.Replace(theCell.CellReference, @"\d+", rowIndex.ToString());
}
private static void InsertRow(SheetData sheetData, Row row)
{
sheetData.InsertAfter(row, currentBottomRow);
currentBottomRow = row;
}
}
social.msdn 上发布的同一问题得到了很好的回答:
忘记尝试设置 rowIndex 和 CellReference 的速度要快得多。而是让它们为空,并使用 AppendChild。这是我改进的代码:
public class MyReport
{
public byte[] Get(List<dbRow> dbRows)
{
// dbRows is the result of "Select col0, col1, ... col21 from dbTable"
foreach (dbRow r in dbRows)
{
Row newRow = new Row();
SetCell(r.string0, newRow);
SetCell(r.int1, newRow);
SetCell(r.string2, newRow);
SetCell(r.string3, newRow);
SetCell(r.string4, newRow);
SetCell(String.Format("{0:MM/dd/yyyy}", r.date5), newRow);
SetCell(r.string6, rowIndex);
SetCell(r.int7, rowIndex);
SetCell(r.string8, rowIndex);
SetCell(r.string9, rowIndex);
SetCell(r.date10.ToString("MM/dd/yyyy"), rowIndex);
SetCell(String.Format("{0:MM/dd/yyyy}", r.date11), rowIndex);
SetCell(String.Format("{0:MM/dd/yyyy}", r.date12), rowIndex);
SetCell(r.string13, rowIndex);
SetCell(String.Format("{0:MM/dd/yyyy}", r.date14), rowIndex);
SetCell(r.int15 ?? 0, rowIndex);
SetCell(String.Format("{0:MM/dd/yyyy}", r.date16), rowIndex);
SetCell(r.string17, rowIndex);
SetCell(r.string18, rowIndex);
SetCell(r.int19, rowIndex);
SetCell(r.string20, rowIndex);
SetCell(r.string21, rowIndex);
sheetData.AppendChild(newRow);
}
private void SetCell(string val, Row theRow)
{ // a NON-SHARED string is going in to the cell
Cell theCell = new Cell();
theCell.CellValue = new CellValue(val);
theCell.DataType = new EnumValue<CellValues>(CellValues.String);
theRow.AppendChild(theCell);
}
protected void SetCell(int val, Row theRow)
{ // an int is going in to the cell
Cell theCell = new Cell();
theCell.CellValue = new CellValue(val.ToString());
theCell.DataType = new EnumValue<CellValues>(CellValues.Number);
theRow.AppendChild(theCell);
}
}
}
我使用 OpenXML v 2.8.1.0 为网站创建 excel 报告。电子表格有 22 列。呈现 15,000 行需要 30 秒,但这对于网页来说太长了。我可以更有效地做到这一点吗?
下面是代码片段(省略了与问题无关的部分)。怀疑我在循环遍历每个单元格以设置其单元格引用,然后还设置每一行的 rowIndex 时效率低下。
我在打开要填充的电子表格的地方遗漏了代码 - 它包含 headers 和示例详细信息行,其中包含我想要的所有格式,但所有值都是空白。
在代码中,我克隆该行,为每个单元格设置值和单元格引用,为该行设置 rowIndex,插入该行,然后从数据库中获取下一行数据并重复。
或者每秒 500 行的速度与 OpenXML 的速度差不多吗?
谢谢。
public class MyReport
{
public byte[] Get(List<dbRow> dbRows)
{
// dbRows is the result of "Select col0, col1, ... col21 from dbTable"
// first 6 rows are the report headers
// row 7 is the blank detail row.
Row templateDetailRow = sheetData.Elements<Row>().Where(r => r.RowIndex == 7).First();
// start inserting data rows at row number 8
uint currentRowPointer = sheetData.Elements<Row>().LastOrDefault().RowIndex + 1; // start adding rows after the current last row
Row currentBottomRow = sheetData.Elements<Row>().LastOrDefault(); // initialize to last row before we start adding rows
foreach (dbRow r in dbRows)
{
Row newRow = (Row)templateDetailRow.Clone();
List<Cell> cells = newRow.Elements<Cell>().OrderBy(c => c.CellReference.Value).ToList();
SetCellsInRow(cells, r, currentRowPointer);
newRow.RowIndex = currentRowPointer;
InsertRow(sheetData, newRow);
currentRowPointer++;
}
}
private void SetCellsInRow(List<Cell> cells, dbRow source, uint rowIndex)
{
SetCell(cells[0], source.string0, rowIndex);
SetCell(cells[1], source.int1, rowIndex);
SetCell(cells[2], source.string2, rowIndex);
SetCell(cells[3], source.string3, rowIndex);
SetCell(cells[4], source.string4, rowIndex);
SetCell(cells[5], String.Format("{0:MM/dd/yyyy}", source.date5), rowIndex);
SetCell(cells[6], source.string6, rowIndex);
SetCell(cells[7], source.int7, rowIndex);
SetCell(cells[8], source.string8, rowIndex);
SetCell(cells[9], source.string9, rowIndex);
SetCell(cells[10], source.date10.ToString("MM/dd/yyyy"), rowIndex);
SetCell(cells[11], String.Format("{0:MM/dd/yyyy}", source.date11), rowIndex);
SetCell(cells[12], String.Format("{0:MM/dd/yyyy}", source.date12), rowIndex);
SetCell(cells[13], source.string13, rowIndex);
SetCell(cells[14], String.Format("{0:MM/dd/yyyy}", source.date14), rowIndex);
SetCell(cells[15], source.int15 ?? 0, rowIndex);
SetCell(cells[16], String.Format("{0:MM/dd/yyyy}", source.date16), rowIndex);
SetCell(cells[17], source.string17, rowIndex);
SetCell(cells[18], source.string18, rowIndex);
SetCell(cells[19], source.int19, rowIndex);
SetCell(cells[20], source.string20, rowIndex);
SetCell(cells[21], source.string21, rowIndex);
}
private void SetCell(Cell theCell, string val, uint rowIndex)
{ // a NON-SHARED string is going in to the cell
theCell.CellValue = new CellValue(val);
theCell.DataType = new EnumValue<CellValues>(CellValues.String);
theCell.CellReference = Regex.Replace(theCell.CellReference, @"\d+", rowIndex.ToString());
}
private void SetCell(Cell theCell, int val, uint rowIndex)
{ // an int is going in to the cell
theCell.CellValue = new CellValue(val.ToString());
theCell.DataType = new EnumValue<CellValues>(CellValues.Number);
theCell.CellReference = Regex.Replace(theCell.CellReference, @"\d+", rowIndex.ToString());
}
private static void InsertRow(SheetData sheetData, Row row)
{
sheetData.InsertAfter(row, currentBottomRow);
currentBottomRow = row;
}
}
social.msdn 上发布的同一问题得到了很好的回答:
忘记尝试设置 rowIndex 和 CellReference 的速度要快得多。而是让它们为空,并使用 AppendChild。这是我改进的代码:
public class MyReport
{
public byte[] Get(List<dbRow> dbRows)
{
// dbRows is the result of "Select col0, col1, ... col21 from dbTable"
foreach (dbRow r in dbRows)
{
Row newRow = new Row();
SetCell(r.string0, newRow);
SetCell(r.int1, newRow);
SetCell(r.string2, newRow);
SetCell(r.string3, newRow);
SetCell(r.string4, newRow);
SetCell(String.Format("{0:MM/dd/yyyy}", r.date5), newRow);
SetCell(r.string6, rowIndex);
SetCell(r.int7, rowIndex);
SetCell(r.string8, rowIndex);
SetCell(r.string9, rowIndex);
SetCell(r.date10.ToString("MM/dd/yyyy"), rowIndex);
SetCell(String.Format("{0:MM/dd/yyyy}", r.date11), rowIndex);
SetCell(String.Format("{0:MM/dd/yyyy}", r.date12), rowIndex);
SetCell(r.string13, rowIndex);
SetCell(String.Format("{0:MM/dd/yyyy}", r.date14), rowIndex);
SetCell(r.int15 ?? 0, rowIndex);
SetCell(String.Format("{0:MM/dd/yyyy}", r.date16), rowIndex);
SetCell(r.string17, rowIndex);
SetCell(r.string18, rowIndex);
SetCell(r.int19, rowIndex);
SetCell(r.string20, rowIndex);
SetCell(r.string21, rowIndex);
sheetData.AppendChild(newRow);
}
private void SetCell(string val, Row theRow)
{ // a NON-SHARED string is going in to the cell
Cell theCell = new Cell();
theCell.CellValue = new CellValue(val);
theCell.DataType = new EnumValue<CellValues>(CellValues.String);
theRow.AppendChild(theCell);
}
protected void SetCell(int val, Row theRow)
{ // an int is going in to the cell
Cell theCell = new Cell();
theCell.CellValue = new CellValue(val.ToString());
theCell.DataType = new EnumValue<CellValues>(CellValues.Number);
theRow.AppendChild(theCell);
}
}
}