詳細については、下部にある私のアップデートを参照してください。
一部のデータをExcelファイル(xlsx形式)として出力しなければならないプロジェクトがあります。プロセスは通常:
ユーザーがアプリケーションの一部のボタンをクリックした
私のコードはDBクエリを実行し、結果を何らかの形で処理します
私のコードは、Excel com相互運用ライブラリまたはいくつかのサードパーティライブラリ(Aspose.Cellsなど)を使用して* .xlsxファイルを生成します
オンラインでこれを行う方法のコード例を簡単に見つけることができますが、これを行うためのより堅牢な方法を探しています。コードをいくつかの設計原則に従って、コードが保守可能で理解しやすいものになっていることを確認します。
以下は、xlsxファイルを生成しようとする私の最初の試みのようなものです。
_var wb = new Workbook();
var ws = wb.Worksheets[0];
ws.Cells[0, 0].Value = "Header";
ws.Cells[1, 0].Value = "Row 1";
ws.Cells[2, 0].Value = "Row 2";
ws.Cells[3, 0].Value = "Row 3";
wb.Save(path);
_
長所:それほどではありません。それは機能するので、それは良いことです。
短所:
上記の短所の一部に対処する1つのソリューションを次に示します。データのテーブルを独自のオブジェクトとして扱い、セルの操作を掘り下げたり他のセル参照を妨害したりすることなく、移動したり変更したりできるようにしました。ここにいくつかの疑似コードがあります:
_var headers = new Block(new string[] { "Col 1", "Col 2", "Col 3" });
var body = new Block(new string[,]
{
{ "Row 1", "Row 1", "Row 1" },
{ "Row 2", "Row 2", "Row 2" },
{ "Row 3", "Row 3", "Row 3" }
});
body.PutBelow(headers);
_
このソリューションの一部として、ブロックのコンテナーを取得し、*。xlsxファイルとしてデータを出力するために必要なセル操作を実行するいくつかのBlockEngineオブジェクトを用意します。 Blockオブジェクトには、フォーマットを関連付けることができます。
長所:
短所:
tableRight.PutToRightOf(tableLeft)
を使用できますが、tableRightとtableLeftの行数が異なる場合は問題が発生します。テーブルを配置するには、エンジンは他のすべてのテーブルを認識する必要があります。これは不必要に複雑に思えます。これは別のルートを取るソリューションです。ここにプロセスがあります:
レポートデータを取得して、選択した形式でxmlファイルを生成します。
次に、xsl変換を使用して、xmlファイルをExcel 2003 XMLスプレッドシートファイルに変換します。
そこから、サードパーティのライブラリを使用して、xmlスプレッドシートをxlsxファイルに変換するだけです。
同様のプロセスを説明し、コード例を含む このページ を見つけました。
長所:
短所:
注:xlsxファイルは実際にはxmlファイルを含むZipファイルですが、xmlのフォーマットは目的に対して複雑すぎるようです。
最後に、SSRSに関連するソリューションを調べましたが、私の目的には膨らんでいるようです。
最初の質問に戻りますが、コードでExcelファイルを生成するための優れたデザインパターンは何ですか。私はいくつかの解決策を考えることができますが、どれも理想的なものとしてはみ出していないようです。それぞれに欠点があります。
更新:そこで、BlockEngineソリューションとXMLスプレッドシートソリューションの両方を試して、同様のXLSXファイルを生成しました。ここにそれらの私の意見があります:
BlockEngineソリューション:
XMLスプレッドシートソリューション:
あなたが本当にうまくいくものを本当に望んでいるなら、「不必要に複雑」という考えに慣れることをお勧めします...それがMicrosoft Officeファイルフォーマットを扱う性質です。
私は「ブロック」のあなたのアイデアが(ちょっと)好きです...私は、テーブルのようなサブクラス化されたブロックオブジェクトを、セルの概念から独立した列と行で作成します。次に、ブロックエンジンを使用して、これらをXSLSファイルに変換します。
私は過去に OpenXML SDK を使用して成功しましたが、ドキュメントを読んでゼロから始めようとしないでください。代わりに、必要なものの正確なコピーをExcelで作成して保存し、提供されているドキュメントリフレクターツールを使用して検査します。これにより、ドキュメントの作成に必要なC#コードが提供され、そこから学習および変更できます。
これは私が過去に頻繁に使用したソリューションです:
テンプレートとして、通常のExcelドキュメント(通常はxlsx形式)を作成します。これには、タイトル、列のデフォルトのフォーマット、タイトルセルのフォーマットなど、すべての列ヘッダーが含まれます。
そのテンプレートをプログラムのリソースに埋め込みます。実行時の最初のステップは、テンプレートを新しいファイルとして抽出し、それを宛先フォルダーに配置することです
interopまたはサードパーティのライブラリを使用して、新しく作成したxlsxにデータを入力します。ハードコードされた列番号を参照しないでください。代わりに、いくつかのメタデータ(列ヘッダーなど)を使用して正しい列を識別してください。
長所:
ブロックアプローチのようなものがよりよく機能するようになりました。たとえば、列スワッピング:正しい列はヘッダーによって識別されるため、ブロックコードで何も変更する必要はありません。
列に一意のフォーマットが設定されている限り、テンプレートを操作することにより、ほとんどのフォーマットをExcelで直接行うことができます。これにより、WYSIWYGの感覚が得られ、コードを記述する必要なく、Excelで使用できるフォーマットオプションを自由に使用できます。
短所:
サードパーティのlibまたはInteropを使用する必要があります。 Interopが遅いと言ったことはありますか?
テンプレートで列ヘッダーが変更されると、コードも調整する必要があります(ただし、予期される列が欠落している場合に通知する検証ルーチンを使用することで簡単に検出できます)
同じ列の異なるセルの動的なフォーマットが必要な場合でも、コードでそれを処理する必要があります
一般的なヒントとして、どのアプローチを選択しても、レイアウトをコンテンツから分離し、宣言型ソリューションを利用することには利点があります。
考慮すべき点が2つあります。
最初について:
生成する必要があるスプレッドシートフォーマットや数式を含めないの場合、実際のXLSXの代わりにCSVまたはタブ区切りファイルを生成するのは非常に簡単です。 Excelはこれらのファイルを開きます。多くの場合、デフォルトでは多くのPCで開かれています。これは列と行の周りのハードコーディングには役立ちませんが、Excelオブジェクトモデルを操作する余分な作業を省きます。
書式設定または数式が必要な場合、特にそれ自体が「ハードコード」されていないスプレッドシートを作成する場合は、Excelオブジェクトモデルでの作業が合理的な方法です。言い換えると、スプレッドシートが相対数式と範囲名を適切に使用している場合は、マジックナンバーのハードコーディングを減らすことができます。
2番目について:
ハードコードされた行と列の参照を使用してセルごとに作業するか、配列/リストコレクションおよびfor
ループを使用してセルの母集団を一般化できます。