モルモルしている

最近はテスト業務ばっかりで書くことがない

EPPlusで表をExcelに出力する

要件:
テーブルにストアド名と出力シート名、出力開始セル名を持っているので設定されたストアドを実行し、得た結果を指定されたシート名、セルに出力しなさい。
※ただし実行環境にExcelはインストールされていません。



(´・ω・) 無理っす!



と思ったが、同僚からEPPlusというものがあると教えてもらってなんとかなりました。
これ今後何回もやることになりそうなので作ったサンプルをまるまま残しておこう。
ちなみにSQLServerとのやり取りはDapperを使っています。
(あ、ちなみにEPPlusのライセンスはLGPLです)

  • やること
  1. NuGetでEPPlusを検索し、インストール
  2. using OfficeOpenXml; using OfficeOpenXml.Style; を追加
  3. コードを書く
    1. 設定テーブルから実行するストアドと出力先情報をリスト(あらかじめ定義しておいたクラス)に取得
    2. 取得した設定ごとにストアドの実行(ストアドは実行した結果値を返す=SELECTするものとする)
    3. 得たデータを指定のシートの指定のセルを開始位置として出力する
    4. 出力ファイルは指定のテンプレートを使って、指定の場所へ指定の名称で保存。
private void button1_Click(object sender, EventArgs e)
        {
            // テンプレートファイル
            FileInfo template = new FileInfo(@"C:\Work\Template.xlsx");
            // 出力先
            string outputdir = @"C:\Work";

            using (var cn = new SqlConnection())
            {
                cn.ConnectionString = "Server=TestServer;Database=TestDB;UID=sa;PWD=sa;";
                var list = new List<storedSet>();

                // ストアド設定をリストで取得
                list = cn.Query<storedSet>("SELECT * FROM StoredSetting").ToList();

                // ここから出力作業
                using (var package = new ExcelPackage(template, true))
                {
                    // 取得したストアド一つごとに
                    foreach (var set in list)
                    {
                        // 出力先シートは名称で設定しているのでIndexをとってくる
                        var index = GetSheetIndex(set.SheetName, template);
                        ExcelWorksheet ws = package.Workbook.Worksheets[index];

                        // 出力開始セルをRangeに設定
                        using (ExcelRange row = ws.Cells[set.CellName])
                        {
                            // ストアドを実行
                            var a = cn.ExecuteReader(set.StoredProcedure, commandType: System.Data.CommandType.StoredProcedure);

                            // ストアドから得た結果のフィールド数を取得
                            var cnt = a.FieldCount;

                            // 開始セルの位置を数値で取得
                            var r = row.Start.Row;
                            var c = row.Start.Column;

                            // 読み込んだ結果を一行ずつ読み込んで出力
                            while (a.Read())
                            {
                                for (int i = 0; i < cnt; i++)
                                {
                                    ws.Cells[r, c + i].Value = a[i];
                                }
                                r += 1;
                            }
                            a.Close();
                        }
                    }
             
                    // 作ったデータをバイト配列にセット(日本語があってるか不明)
                    Byte[] bin = package.GetAsByteArray();
                    // ファイルを出力
                    string file = outputdir + @"\Dekita.xlsx";
                    File.WriteAllBytes(file, bin);
                }
            }

            MessageBox.Show("出力完了");
        }

        private int GetSheetIndex(string sheetName,FileInfo filePath)
        {
            using (var package = new ExcelPackage(filePath))
            {
                using (var stream = File.OpenRead(filePath.FullName))
                {
                    package.Load(stream);
                }

                int i = 0;
                foreach(var sh in package.Workbook.Worksheets)
                {
                    if (sh.Name == sheetName)
                    {
                        return i + 1;
                    }
                    i += 1;
                }
            }
            return -1;
        }
    }

    public class storedSet
    {
        public int Id { get; set; }
        public string StoredProcedure { get; set; }
        public string SheetName { get; set; }
        public string CellName { get; set; }
    }

参考URL:
C# - EPPlusを使ったExcel Hello World - Qiita
C#でエクセルシートへアクセス
c# - Get Cell's Row number using EPPlus - Stack Overflow

シートのIndexを取得するところはまるまま二番目のサイト様のやり方を使わせてもらった。助かります。