将一个大型数据查询(超过60k行)导出到Excel。

19 浏览
0 Comments

将一个大型数据查询(超过60k行)导出到Excel。

我在内部Web应用程序中创建了一个报告工具。报告以GridView的形式显示所有结果,并使用JavaScript逐行读取GridView的内容到Excel对象中。JavaScript继续在不同的工作表上创建一个数据透视表。

不幸的是,我没有预料到GridView的大小会导致浏览器过载问题,如果返回的天数超过几天。应用程序每天有几千条记录,假设每月有60k条记录,理想情况下,我希望能够返回一年内的所有结果。行数导致浏览器挂起或崩溃。

我们使用ASP.NET 3.5在Visual Studio 2010上使用SQL Server,并且预期的浏览器是IE8。报告包括一个GridView,根据用户选择的人口从一系列存储过程中获取数据。GridView位于UpdatePanel中:

我当时对我的团队比较陌生,所以我按照他们的惯例将存储过程返回到一个DataTable中,并在代码后台中使用它作为DataSource:

(我知道你在想什么!但是是的,我之后学到了更多关于参数化的知识。)

LINQToDataTable函数并没有什么特别之处,只是将列表转换为DataTable。

对于几千条记录(最多几天),这个工作得很好。GridView显示结果,用户可以点击一个按钮来启动JScript导出器。外部JavaScript函数将每一行读入Excel工作表,然后使用它创建一个数据透视表。数据透视表很重要!

我要做的是创建一个可以处理这些数据并将其处理成Excel的解决方案(可能是客户端)。有人可能会建议使用HtmlTextWriter,但据我所知,它不允许自动生成数据透视表,并创建一个烦人的弹出警告...

我尝试过的方法有:

- 填充JSON对象 - 我仍然认为这有潜力,但我还没有找到使其工作的方法。

- 使用SQLDataSource - 我似乎无法从中获取任何数据。

- 分页并遍历页面 - 进展不一,通常很难看,而且我仍然有一个问题,即每个显示的页面都会查询和返回整个数据集。

我仍然非常乐意接受其他解决方案,但我一直在追求JSON理论。我有一个可以从DataTable生成JSON对象的工作服务器端方法。我无法弄清楚如何将该JSON传递到(外部)exportToExcel JavaScript函数...

有人可以展示一个如何将此JSON对象传递到外部JS函数的示例吗?或者任何其他导出到Excel的解决方案。

0
0 Comments

问题的原因是需要导出一个包含60k+行的大数据查询到Excel中,但是不希望使用第三方插件解决这个问题。

解决方法是使用displaytag来显示查询结果。可以设置每页显示的行数来解决过载问题。然后,可以设置displaytag允许导出到Excel。

但是,有人建议不要使用第三方库来解决问题,尤其是像displaytag这样的轻量级库。因为它们可以成为你最好的朋友,避免重新发明轮子。

0
0 Comments

问题的原因:需要将一个包含60,000+行的大型数据查询导出到Excel中。

解决方法:可以通过使用Microsoft Open XML SDK的Open XML Writer来以相对高效的方式处理这个问题。

具体步骤如下:

1. 安装Microsoft Open SDK(如果尚未安装,可在Google上搜索“download microsoft open xml sdk”进行下载)。

2. 创建一个控制台应用程序。

3. 添加对DocumentFormat.OpenXml的引用。

4. 添加对WindowsBase的引用。

5. 尝试运行下面的测试代码(需要一些using语句)。

using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using (var workbook = SpreadsheetDocument.Create("SomeLargeFile.xlsx", SpreadsheetDocumentType.Workbook))
{
    List attributeList;
    OpenXmlWriter writer;
    workbook.AddWorkbookPart();
    WorksheetPart workSheetPart = workbook.WorkbookPart.AddNewPart();
    writer = OpenXmlWriter.Create(workSheetPart);
    writer.WriteStartElement(new Worksheet());
    writer.WriteStartElement(new SheetData());
    for (int i = 1; i <= 50000; ++i)
    {
        attributeList = new List();
        // this is the row index
        attributeList.Add(new OpenXmlAttribute("r", null, i.ToString()));
        writer.WriteStartElement(new Row(), attributeList);
        for (int j = 1; j <= 100; ++j)
        {
            attributeList = new List();
            // this is the data type ("t"), with CellValues.String ("str")
            attributeList.Add(new OpenXmlAttribute("t", null, "str"));
            // it's suggested you also have the cell reference, but
            // you'll have to calculate the correct cell reference yourself.
            // Here's an example:
            //attributeList.Add(new OpenXmlAttribute("r", null, "A1"));
            writer.WriteStartElement(new Cell(), attributeList);
            writer.WriteElement(new CellValue(string.Format("R{0}C{1}", i, j)));
            // this is for Cell
            writer.WriteEndElement();
        }
        // this is for Row
        writer.WriteEndElement();
    }
    // this is for SheetData
    writer.WriteEndElement();
    // this is for Worksheet
    writer.WriteEndElement();
    writer.Close();
    writer = OpenXmlWriter.Create(workbook.WorkbookPart);
    writer.WriteStartElement(new Workbook());
    writer.WriteStartElement(new Sheets());
    // you can use object initialisers like this only when the properties
    // are actual properties. SDK classes sometimes have property-like properties
    // but are actually classes. For example, the Cell class has the CellValue
    // "property" but is actually a child class internally.
    // If the properties correspond to actual XML attributes, then you're fine.
    writer.WriteElement(new Sheet()
    {
        Name = "Sheet1",
        SheetId = 1,
        Id = workbook.WorkbookPart.GetIdOfPart(workSheetPart)
    });
    writer.WriteEndElement(); // Write end for WorkSheet Element
    writer.WriteEndElement(); // Write end for WorkBook Element
    writer.Close();
    workbook.Close();
}

需要注意的是,Excel中的行编号从1开始,而不是从0开始。如果以0为索引开始编号行,将会导致“Corrupt file”错误。

另外,如果处理的数据集非常大,不要使用ToList()方法,而是使用数据读取器(data reader)的方式流式处理数据。例如,可以使用IQueryable并在foreach循环中使用它。不要一次性将所有数据都加载到内存中,否则可能会遇到内存不足或内存使用率过高的限制。

对于需要流式传输的大型文件,可以尝试直接提供输出流(output stream),而不是文件名。然而,根据这个回答(OpenXml and HttpResponse.OutputStream),OpenXML库需要能够返回到开头,因此在主机文件之前保存到文件似乎是处理大量数据的唯一选择。

这些步骤可以帮助你导出大型数据查询到Excel中。一旦理解了底层的XML架构,这个过程就会更加清晰。可以花一些时间查看有效的xlsx文件中的底层xml结构,以便更好地理解。

0
0 Comments

出现的原因:

该问题的原因是因为要导出的数据量非常大,超过了60k+行,导致在客户端处理和显示时出现了超时和浏览器问题。

解决方法:

一种解决方法是使用服务器端方法来处理导出操作。可以在页面上添加一个"Export"按钮,将其与服务器端的方法绑定,在该方法中获取数据集并将其转换为CSV格式。然后调整响应头,使浏览器将其视为下载。实现服务器端的记录分页后,可以解决超时和浏览器问题。

另一种解决方法是使用C#中的API来进行高级工作簿Excel文件的创建。可以在C#中对数据进行透视和操作,然后将其导出为CSV格式。

这些解决方法都是服务器端的解决方案,可以在保证导出大数据查询的同时,仍然能够通过编程方式操作Excel生成透视表。

0