5

内部 Web アプリケーションの一部としてレポート ツールを作成しました。レポートでは、すべての結果が GridView に表示されます。JavaScript を使用して、GridView の内容を行ごとに Excel オブジェクトに読み込みました。JavaScript は、別のワークシートにピボットテーブルを作成します。

残念ながら、数日以上が返された場合、GridView のサイズがブラウザーの過負荷の問題を引き起こすとは予想していませんでした。アプリケーションには 1 日あたり数千件のレコードがあり、たとえば 1 か月あたり 60k としましょう。理想的には、すべての結果を最大 1 年間返すことができるようにしたいと考えています。行数が原因で、ブラウザがハングまたはクラッシュします。

Visual Studio 2010 と SQL Server で ASP.NET 3.5 を使用しており、予想されるブラウザーは IE8 です。レポートは、ユーザーが選択した母集団に応じて、いくつかのストアド プロシージャの 1 つからデータを取得するグリッドビューで構成されます。gridview は UpdatePanel にあります。

<asp:UpdatePanel ID="update_ResultSet" runat="server">
<Triggers>
    <asp:AsyncPostBackTrigger ControlID="btn_Submit" />
</Triggers>
<ContentTemplate>
<asp:Panel ID="pnl_ResultSet" runat="server" Visible="False">
    <div runat="server" id="div_ResultSummary">
        <p>This Summary Section is Automatically Completed from Code-Behind</p>
    </div>
        <asp:GridView ID="gv_Results" runat="server" 
            HeaderStyle-BackColor="LightSkyBlue" 
            AlternatingRowStyle-BackColor="LightCyan"  
            Width="100%">
        </asp:GridView>
    </div>
</asp:Panel>
</ContentTemplate>
</asp:UpdatePanel>

私は自分のチームに比較的慣れていなかったので、sproc を DataTable に返し、それをコード ビハインドの DataSource として使用するという典型的な方法に従いました。

    List<USP_Report_AreaResult> areaResults = new List<USP_Report_AreaResult>();
    areaResults = db.USP_Report_Area(ddl_Line.Text, ddl_Unit.Text, ddl_Status.Text, ddl_Type.Text, ddl_Subject.Text, minDate, maxDate).ToList();
    dtResults = Common.LINQToDataTable(areaResults);

    if (dtResults.Rows.Count > 0)
    {
        PopulateSummary(ref dtResults);
        gv_Results.DataSource = dtResults;
        gv_Results.DataBind();

(私はあなたが何を考えているか知っています!しかし、はい、それ以来、パラメーター化について多くのことを学びました。)

LINQToDataTable 関数は特別なものではなく、リストをデータテーブルに変換するだけです。

数千のレコード (数日まで) の場合、これはうまく機能します。GridView は結果を表示し、ユーザーがクリックして JScript エクスポーターを起動するボタンがあります。外部 JavaScript 関数は、各行を Excel シートに読み取り、それを使用してピボットテーブルを作成します。ピボットテーブルは重要です!

function exportToExcel(sMyGridViewName, sTitleOfReport, sHiddenCols) {
//sMyGridViewName = the name of the grid view, supplied as a text
//sTitleOfReport = Will be used as the page header if the spreadsheet is printed
//sHiddenCols = The columns you want hidden when sent to Excel, separated by semicolon (i.e. 1;3;5).
//              Supply an empty string if all columns are visible.

var oMyGridView = document.getElementById(sMyGridViewName);

//If no data is on the GridView, display alert.
if (oMyGridView == null)
    alert('No data for report');
else {
    var oHid = sHiddenCols.split(";");  //Contains an array of columns to hide, based on the sHiddenCols function parameter
    var oExcel = new ActiveXObject("Excel.Application");
    var oBook = oExcel.Workbooks.Add;
    var oSheet = oBook.Worksheets(1);
    var iRow = 0;
    for (var y = 0; y < oMyGridView.rows.length; y++)
    //Export all non-hidden rows of the HTML table to excel.
    {
        if (oMyGridView.rows[y].style.display == '') {
            var iCol = 0;
            for (var x = 0; x < oMyGridView.rows(y).cells.length; x++) {
                var bHid = false;
                for (iHidCol = 0; iHidCol < oHid.length; iHidCol++) {
                    if (oHid[iHidCol].length !=0 && oHid[iHidCol] == x) {
                        bHid = true;
                        break; 
                    } 
                }
                if (!bHid) {
                    oSheet.Cells(iRow + 1, iCol + 1) = oMyGridView.rows(y).cells(x).innerText;
                    iCol++;
                }
            }
            iRow++;
        }
    }

私がやろうとしていること:このデータを処理して Excel に処理できるソリューション (おそらくクライアント側) を作成します。誰かがHtmlTextWriterの使用を提案するかもしれませんが、ピボットテーブルの自動生成を許可せず、不快なポップアップ警告を作成することがわかっています....

私が試したこと:

  • JSON オブジェクトの作成 -- これにはまだ可能性があると思いますが、機能させる方法を見つけていません。
  • SQLDataSource の使用 -- データを取り戻すために使用できないようです。
  • ページの改ページとループ -- 進行状況はまちまちです。一般的には醜いですが、表示されるページごとにデータセット全体がクエリされて返されるという問題がまだあります。

更新: 私はまだ代替ソリューションに対して非常にオープンですが、JSON 理論を追求してきました。DataTable から JSON オブジェクトを生成するサーバー側のメソッドがあります。その JSON を (外部の) exportToExcel JavaScript 関数に渡す方法がわかりません....

    protected static string ConstructReportJSON(ref DataTable dtResults)
    {
        StringBuilder sb = new StringBuilder();
        sb.Append("var sJSON = [");
        for (int r = 0; r < dtResults.Rows.Count; r++)
        {
            sb.Append("{");
            for (int c = 0; c < dtResults.Columns.Count; c++)
            {
                sb.AppendFormat("\"{0}\":\"{1}\",", dtResults.Columns[c].ColumnName, dtResults.Rows[r][c].ToString());
            }
            sb.Remove(sb.Length - 1, 1); //Truncate the trailing comma
            sb.Append("},");
        }
        sb.Remove(sb.Length - 1, 1);
        sb.Append("];");
        return sb.ToString();
    }

このJSONオブジェクトを外部JS関数に運ぶ方法の例を誰かが示すことができますか? または、Excel にエクスポートするためのその他のソリューション。

4

4 に答える 4

1

通常、これはサーバー側のメソッドに接続された[エクスポート]コマンドボタンを使用して処理し、データセットを取得してCSVに変換します。次に、応答ヘッダーを調整すると、ブラウザーはそれをダウンロードとして扱います。これがサーバー側のソリューションであることは知っていますが、サーバー側のレコードページングを実装するまでタイムアウトとブラウザーの問題が発生し続けるため、検討することをお勧めします。

于 2012-07-07T01:13:08.973 に答える
1

結果を表示するためにdisplaytagを使用しようとします。ページごとに特定の数を表示するように設定できます。これにより、過負荷の問題が解決するはずです。次に、displaytag を設定して Excel エクスポートを許可します。

于 2012-07-06T23:02:44.430 に答える
0

この問題を開始してからほぼ 1 週間半が経過しましたが、ようやくすべてをある程度機能させることができました。他の誰かがより効率的でより良い「ベストプラクティス」の方法を持っているかどうかを確認するために、回答をマークするのを一時的に待ちます.

JSON 文字列を生成することで、JavaScript を GridView から切り離しました。JSON は、データが入力されるときにコード ビハインドで生成されます。

    protected static string ConstructReportJSON(ref DataTable dtResults)
    {
        StringBuilder sb = new StringBuilder();
        for (int r = 0; r < dtResults.Rows.Count; r++)
        {
            sb.Append("{");
            for (int c = 0; c < dtResults.Columns.Count; c++)
            {
                sb.AppendFormat("\"{0}\":\"{1}\",", dtResults.Columns[c].ColumnName, dtResults.Rows[r][c].ToString());
            }
            sb.Remove(sb.Length - 1, 1); //Truncate the trailing comma
            sb.Append("},");
        }
        sb.Remove(sb.Length - 1, 1);
        return String.Format("[{0}]", sb.ToString());
    }

次のようなデータの文字列を返します。

[ {"Caller":"John Doe", "Office":"5555","Type":"Incoming", など},

{"Caller":"Jane Doe", "Office":"7777", "Type":"Outgoing", etc}, {etc} ]

以下を使用して、UpdatePanel の Literal にテキストを割り当てることで、この文字列を非表示にしました。

    <div id="div_JSON" style="display: none;">
            <asp:Literal id="lit_JSON" runat="server" /> 
    </div>

JavaScript は、div の内容を読み取ることによってその出力を解析します。

function exportToExcel_Pivot(sMyJSON, sTitleOfReport, sReportPop) {
     //sMyJSON = the name, supplied as a text, of the hidden element that houses the JSON array.
     //sTitleOfReport = Will be used as the page header if the spreadsheet is printed.
     //sReportPop = Determines which business logic to create a pivot table for.

var sJSON = document.getElementById(sMyJSON).innerHTML;
var oJSON = eval("(" + sJSON + ")");

 //    DEBUG Example Test Code
 //    for (x = 0; x < oJSON.length; x++) {
 //        for (y in oJSON[x])
 //            alert(oJSON[x][y]); //DEBUG, returns field value
 //            alert(y); //DEBUG, returns column name
 //    }


//If no data is in the JSON object array, display alert.
if (oJSON == null)
    alert('No data for report');
else {
    var oExcel = new ActiveXObject("Excel.Application");
    var oBook = oExcel.Workbooks.Add;
    var oSheet = oBook.Worksheets(1);
    var oSheet2 = oBook.Worksheets(2);
    var iRow = 0;
    var iCol = 0;

        //Take the column names of the JSON object and prepare them in Excel
        for (header in oJSON[0])
        {
            oSheet.Cells(iRow + 1, iCol + 1) = header;
            iCol++;
        }

        iRow++;

        //Export all rows of the JSON object to excel
        for (var r = 0; r < oJSON.length; r++)
        {
            iCol = 0;
            for (c in oJSON[r]) 
                    {
                        oSheet.Cells(iRow + 1, iCol + 1) = oJSON[r][c];
                        iCol++;
                    } //End column loop
            iRow++;
        } //End row

文字列出力と JavaScript の「eval」解析はどちらも驚くほど高速に動作しますが、JSON オブジェクトのループは思ったよりも少し遅くなります。

この方法は、約 10 億文字のデータに制限されると思います。メモリ テストがどのように機能するかによっては、それより少ないかもしれません。(私は、おそらく 1 日あたり最大 100 万文字を見ていると計算したので、レポートから 1 年以内に問題ないはずです。)

于 2012-07-10T19:21:58.090 に答える