C# WinFormsトーナメントデータのデータベースへの保存 — Tim Coreyによる徹底解説
"C# App From Start to Finish"シリーズの第19回では、Tim Coreyがプロジェクトの最も重要なマイルストーンの一つ、つまり完全に構築されたWinFormsトーナメントをデータベース(およびテキストファイル)に保存する方法を解説します。 WinFormsはWindowsデスクトップアプリケーションを構築するためのフレームワークであり、実際の場面でのデータ永続性を示すのに最適な選択です。
この記事は完全に第19課 – トーナメントフォームの作成(パート5)に基づいており、ティム自身のステップバイステップの思考、デバッグプロセス、コーディングパターンに従っています。
理論を提示するのではなく、Tim は実際のアプリケーションコードを使って、モデルがどのように保存され、復元され、デバッグされ、そして問題が発生した際にどのように修正されるかを示しています。 これにより、このレッスンはWinFormsにおける実践的なデータ永続化を理解するために特に価値があります。
はじめに
冒頭で、ティムはレッスン19を紹介し、今日はついにトーナメント作成フォームが完成する日であることを説明します。 彼は、このフォームがこれまでで最大のものであり、多くの可動部分があり圧倒されることもあると認めています。 このレッスンでは、WinFormsのイベント駆動モデルと迅速なアプリケーション開発機能を適用して、実際のフォームを完成させる方法を学びます。
ティムは視聴者に、複雑さが扱いやすい部分に分解されていること、そして今日の焦点はSQLデータベースまたはテキストファイルにトーナメントデータを保存するために必要な最終的なロジックであり、それで機能が完成することを保証します。 WinFormsは、迅速なアプリケーション開発(RAD)や社内業務ツール、軽量なユーティリティの構築に最適です。比較的シンプルなイベント駆動モデルと膨大なオンラインリソースにより、新しい開発者が学びやすいです。
Visual Studioで新しいプロジェクトを作成する
Visual Studio を使えば、Windows Forms アプリの開始は簡単です。 Visual Studio を開き、スタートウィンドウから"新しいプロジェクトの作成"を選択します。 "新しいプロジェクトを作成"ダイアログで、検索バーに"Windows Forms App"と入力してください。これにより、必要なテンプレートがすぐに表示されます。 C#を言語として、Windowsをプラットフォームとしてフィルタリングすることで、オプションを絞り込んでください。
"Windows Forms App (.NET Framework)"プロジェクトタイプを見つけたら、それを選択し、次へをクリックしてください。 "新しいプロジェクトを構成する"ウィンドウで、プロジェクトに名前を付けます(例えば、HelloWorld)、場所を選択し、作成をクリックします。 Visual Studio は新しいソリューションを生成し、アプリケーションのグラフィカルユーザーインターフェースとして機能するメインフォームを開きます。 このフォームは、ユーザーインターフェイスを設計し、コントロールを追加する場所です。これにより、Windowsデスクトップアプリケーションの基盤を築きます。 このテンプレートには、.NET Frameworkに必要なファイルや参照がすべて含まれているため、アプリの機能や特長の構築にすぐに集中することができます。
トーナメント作成ボタンのロジックをレビューする
ティムはレビューから始めます。 彼は、すべてがプログラム内の"トーナメント作成"ボタンから始まると説明しています。 C# WinFormsプログラムでは、特定のユーザーアクションに応じてコードを実行するためにイベントハンドラーが記述されます。例えば、"トーナメント作成"ボタンをクリックするなどです。 これまでに、アプリケーションはすでに:
ユーザー入力の検証
トーナメントオブジェクトを構築しました
- メモリ内でラウンドとマッチアップを作成しました
タイムが説明するのは、欠けている部分はそのデータを永続化することです。 以前、このアプリはトーナメント、賞金、およびエントリーを保存できましたが、ラウンド情報が欠落していました。 それがこのレッスンで解決することです。
トーナメントをSQLに保存する: 全体像
ティムはSQLコネクタのCreateTournamentメソッドに移動し、データの保存は明確なパターンに従うことを視聴者に思い出させます。
トーナメント自体を節約
トーナメントIDを取得する
賞品を節約
節約 エントリー
- 次に: ラウンドと試合を節約
注意: この保存順序に従うことが重要です。これにより、すべての関連データが正しく関連付けられ、アプリケーションのデータ整合性が維持されます。
ティムはパターンが良いことを強調しており、このレッスンは以前に確立された同じパターンに従っています。
WinFormsは、ボタン、テキストボックス、ラベルのような再利用可能なUI要素の作成もサポートしており、アプリケーションのデータ構造の一貫性を維持するのに役立ちます。
データ構造の複雑性を理解する
ここでティムが立ち止まって、ラウンドの節約がなぜ複雑なのかを説明します。
トーナメントにはラウンドがあります
・各ラウンドは、MatchupModelのリストです。
各マッチアップにはMatchupEntryModelオブジェクトが含まれています
ティムは、これはリストのリストであり、この段階での複雑性は通常のことだと説明しています。 彼は視聴者にパニックにならないように勧めています。これは現実世界のデータをモデル化した自然な結果に過ぎません。
彼はまた、WinFormsアプリケーションは、データグリッドやUIコントロールのようなコンポーネントを使用して構築され、開発者が機能豊富なデスクトップアプリケーションを効率的に作成するのに役立つことを指摘しています。 Windows Formsクラスライブラリのすべての視覚要素は、Controlクラスから派生しており、一貫した基盤を提供して、ユーザーインターフェースを構築およびカスタマイズすることができます。
保存順が重要な理由
ビデオの中で最も重要な説明の一つがここで行われます。
ティムによると、データは順序に保存しなければならない、なぜなら:
親の試合IDが存在するまで、試合エントリーを保存できません。
ラウンドは、前のラウンドにIDが付与されるまで次のラウンドを参照することはできません。
彼は、オブジェクトが同じメモリアドレスを参照しているため、一度IDがどこかで設定されると、すべての参照が自動的に更新されると説明しています。 しかし、開発者は、IDが割り当てられる過程でオブジェクト参照を変更する必要があるかもしれません。これは、C# WinFormsアプリケーションにおいて、ユーザーの操作やデータの変化に応答するイベント駆動型のプロセスの一部として一般的なことです。
すべてのモデルにIDを持たせることの確認
ティムは重要な修正点を指摘します。MatchupEntryModelにはまだIDプロパティがありません。
すぐに必要でなくても、ティムはとにかくそれを追加します。すべてのデータベース対応モデルには、一貫性と将来の使用のためにIDが必要であると説明しています。 既定では、Windows FormsアプリケーションはForm1.Designer.csのようなファイルを使用してUIコードを自動生成し、アプリケーションの標準的な構造と動作を確保します。
ロジックを簡単なステップに分解する
このセクションでは、C# WinFormsアプリケーションでデータを保存する方法についてのチュートリアルを提供します。
ティムは彼の好きな教えのたとえ話の一つを使います。それは象を一口ずつ食べるということです。
彼は節約のロジックを明確なステップに分けます。
各ラウンドをループします
各ラウンド内で、マッチアップをループします
各マッチアップを節約してください
マッチアップエントリーをループする
- 各エントリーを節約してください
各ステップはそれぞれ単純ですが、一緒にすることで強力になります。
Visual Studioのシンプルなドラッグアンドドロップのビジュアルデザイナーにより、WinFormsは社内ツール、プロトタイプ、シンプルなアプリケーションを構築するのに優れています。
ラウンドとマッチアップをループする
ティムは、それぞれのラウンドがMatchupModelのリストであるラウンドのリストをループする方法を示します。
彼は最初に故意にvarを避け、その理由を説明しています。明示的な型は、特にネストされたリストを扱う際に、開発者が何をループしているか理解する助けになるからです。 Windows Forms開発で異なるプログラミング言語を扱う際には、クリアなコードが特に重要です。これにより、メンテナンスの向上や複数言語へのローカライズがサポートされます。
また、彼は重要な哲学を共有しています。
"最良のコードは、新人の開発者でも理解できるコードです。"
Windows Formsアプリケーションはイベント駆動型であり、Microsoft for .NET Frameworkによってサポートされています。
マッチアップ挿入ストアドプロシージャの作成
TimはSQLに切り替え、spMatchups_Insertを作成します。
彼はフィールドを明確に説明します。
トーナメントID
対戦ラウンド
- 勝者ID (null許容)
追加のフィールドとして、日付などを含めることで対戦がいつ行われたかを追跡することができます。
ティムはこの段階で意図的に勝者を決めません。 対戦が不戦勝であっても、彼は実際の試合と同じロジックを使用して、後で勝者を処理することを好みます。
Windows Formsは、既存のWindows APIをマネージドコードでラップすることにより、ネイティブのWindowsユーザーインターフェイス共通コントロールにアクセスを提供します。
マッチアップエントリーの保存とNULLの処理
Timは別のストアドプロシージャを作成します: spMatchupEntries_Insert。
彼は説明します:
スコアがNULLなのは、ゲームがまだ行われていないためです。
- NULLはゼロと同じではありません
後のラウンドではTeamCompetingがNULLになる可能性があります。
彼は、ゼロが実際の値である理由を説明するために、サッカーとゴルフを使った記憶に残る例を挙げ、NULLがまだ値が存在しない状態を意味することを説明します。
アプリケーション設定は、Windows Formsプロジェクト内で、NULL値がコントロールで表示または処理される方法など、さまざまなデータシナリオを扱うように構成できます。
Windows Formsは、Microsoft .NET、.NET Framework、またはMonoの一部として含まれています。
.NET Frameworkアプリケーションの機能と特徴
.NET Framework上に構築されたWindows Formsアプリは、モダンなWindowsデスクトップアプリケーションを作成するための強力な機能セットを提供します。 Windows Forms (WinForms) を使用すると、直感的でインタラクティブなユーザーインターフェイスを簡単にデザインできる豊富なグラフィカルユーザーインターフェイス (GUI) ライブラリにアクセスできます。 WinFormsは、Microsoft .NET、.NET Framework、およびMonoに含まれる無料のオープンソースフレームワークであり、マネージドコードを通じてネイティブなWindowsコントロールとWindows APIとのシームレスな統合を提供します。
Visual Studio IDE は、Windows Forms デザイナーのようなツールを用いて、開発者の体験を向上させます。このデザイナーを使用すると、ボタンやテキストボックス、ラベルなどの一般的なコントロールをドラッグアンドドロップしてフォームに直接配置することができます。 この視覚的なアプローチにより、UIデザインが迅速化され、プロパティウィンドウを使用してプロパティやイベントをカスタマイズできます。 コード編集、デバッグ、プロジェクト管理の内蔵サポートにより、Visual Studio はWindowsデスクトップアプリケーションの構築、テスト、改善のプロセスを効率化します。 ビジネスツール、ユーティリティ、教育用ソフトウェアを作成する場合でも、.NET Framework と WinForms は、機能豊富でレスポンシブなユーザーフレンドリーなアプリケーションを提供するための強力なプラットフォームを提供します。
編集と続行によるデバッグ
例外が発生したとき、Timは慌てずに教えます。
彼はVisual StudioのEdit and Continue機能を使用して、以下を行います:
- 実行を一時停止
ヌルチェックを挿入します
アプリを再起動せずに実行を再開してください。
キーボードショートカット、例えば"Ctrl"キーの組み合わせ(例:"Ctrl + Alt + X"でツールボックスを開く)を使用すると、Visual StudioでのデバッグやUIコントロールへのアクセスを高速化できます。
彼はどのようにするかを示します。
TeamCompeting が null かどうかを確認してください
*.IDをアクセスする代わりにnullをSQLに渡します。
ParentMatchupに同じロジックを適用します。
これは、実際のデバッグワークフローであり、ティムが使用しているものとまったく同じです。
Visual Studioは、Windows Formsデザイナーを含むC#開発向けの幅広い機能とツールを提供しています。
SQLでデータを検証する
2つの小さなバグを修正した後、Timはデータベースを照会します。
彼が確認します:
対戦が正しく保存されます
・丸められた数字は正確です
- 番狂わせのロジックは動作します
親子関係が正しいです
保存後にデータベース内の正しい関係性およびデータを確認してください。このビジュアルフィードバックは、アプリケーションのロジックが意図したとおりに機能していることを検証するために重要です。
Tim は、非常に複雑な機能でわずか2つのエラーしか発生しなかったことを指摘し、その成功は計画、パターン、そして作業を小さな部分に分割することにあるとしています。
Windows Forms はデスクトップ、ノートパソコン、およびタブレット PC のクライアントアプリケーションを作成するためのプラットフォームを提供し、Windows 開発における多様性を備えた選択肢となります。
コンパイルと検索メソッドの準備
ティムは、未完成の部分に取り組む前にプロジェクトがまだコンパイルされることを確認して始めます。 1:17:08に、彼はシステムが文字列をメソッドに渡し、テキストファイルから取得された1つ以上のMatchupEntryModelオブジェクトを返すことを説明します。
1:17:40で、TimはLookupTeamById(int id)というメソッドを実装します。 彼は、データがテキストファイルに保存されるとき、保存されるのはIDのみであり、完全なオブジェクトではないと説明しています。 したがって、データをロードする際に、アプリケーションはそのIDを完全なTeamModelに復元しなければなりません。
Timは、これは新しいロジックではないことを指摘しています。彼は、ファイルからすべてのチームをロードする際に既に使用されているパターンを単に再利用しているだけです。彼は、この再利用が意図的であり、コードを適切に構造化することの主要な利点であることを強調しています。 開発者は、類似のロジックを実装する際に、既存のメソッドや公式ドキュメントを参照して追加の指導を受けることができます。
Windows Formsは、GUI開発のための以前のより複雑なC++ベースのMicrosoft Foundation Class Libraryの代替と見なされています。
GlobalConfigでファイルパスを集中管理する
1:20:27のところで、ティムは一旦止めて、設計上の問題を指摘しました:ファイル名がどこにでも渡されていますが、それは定数であるべきです。 彼はこれが"ばかげている"と率直に言っています。
これを修正するために、ティムはファイル名の定数をGlobalConfigに移動し、公開します。 1:21:33の時点で、彼はこれによりファイルパスを複数のメソッド層を通して渡すことを避けられると説明しています。 Visual Studioのソリューションエクスプローラーは、これらのプロジェクトファイルや全体の構成を管理するのに役立ち、そのような定数を見つけて更新するのを容易にします。
しかし、1:22:24の時点で、ティムは欠点について正直に述べています。それは、これらの定数が現在、GlobalConfigとTextConnectorの2か所に存在していることです。 彼はこれをDRY(Don't Repeat Yourself)の違反と明言しており、後でリファクタリングすべきだと指摘していますが、今日はその日ではありません。
重要なのは、Windows Forms が Microsoft Foundation Class (MFC) のようなデフォルトのアプリケーションフレームワークを提供していないことです。
文字列をマッチアップエントリーモデルに変換する
1:24:37 で、Tim が ConvertStringToMatchupEntryModel を実装し始めます。 彼は、マッチアップエントリがパイプで区切られたIDとして保存されているので、最初のステップは文字列をパイプで分割することだと説明しています。|)。 ナビゲーションやレイアウトのためにページを主要なUIコンテナとして使用するWebアプリケーションとは異なり、WinFormsはフォームを使用してユーザーインターフェイスを整理します。
1:25:17までに、彼は各IDをループし、マッチアップエントリファイルからそれを調べ、対応するモデルを出力リストに追加します。このパターンは一貫性があります。
読み込む → 変換する → IDでフィルターする → モデルを返す
ティムは一貫性が後々のデバッグを可能にすることを強調しています。
Windows Formsアプリケーションは、C#やVisual Basicといった.NETプログラミング言語を使用して開発することができます。
ConvertToMatchupEntryModels拡張の構築
1:27:56に、Tim は拡張メソッド ConvertToMatchupEntryModels(List< string>) を作成します。 そのプロセスを導くために、彼は既存の変換メソッド(PersonModel用)をコピーし、それを単なるパターンの参考として使用します。
1:30:28 までに、ティムは列を明示的にマッピングします。
列 0 → ID
列 1 → TeamCompeting ID
Column 2 → スコア
- 列 3 → ParentMatchup ID
彼は、保存された値は単なるIDであるため、フルなオブジェクトは検索メソッドを使用して再構築されなければならないと説明しています。 WinForms のいくつかのUIコンポーネントやテーマは、Microsoft Office からインスピレーションを受けています。たとえば、Office 2019 カラフルや Office 2019 ブラックなど、親しみやすいユーザーエクスペリエンスを提供します。
DevExpressのようなサードパーティベンダーは、WinForms用の包括的なUIコンポーネントスイートを提供しています。
親の対戦を安全に処理する
1:38:49時点で、ティムは主要な問題を指摘します。それは、親マッチアップが存在しない可能性があることです(特に第一ラウンドで)。 欠落したIDでFirst()を呼び出すとアプリがクラッシュします。
彼の修正は1:39:09でint.TryParseを使用しています。 解析に失敗した場合、ParentMatchup は null に設定されます。 ティムは、これがまさに1回戦の対戦で起こるべきことだと慎重に説明します。 新しい機能と修正は、WinFormsやサードパーティライブラリの各リリースに含まれることが多く、そのようなシナリオの処理を改善します。
彼は、クラッシュが許容されるのは、例えば無効なチームIDのように、無効なデータが決して存在してはならない場合のみであると強調しています。
DevExpress WinFormsサブスクリプションには、190以上のUIコントロールとライブラリが含まれており、強力なアプリケーションを構築するための幅広いオプションが提供されます。
マッチアップとエントリーをファイルに保存する
1:44:00で、ティムはデータ保存に移ります。 彼はすべての対戦を読み込み、次に利用可能なIDを決定して割り当て、次に対戦エントリーの保存に移ります。 データを保存した後、WinFormsアプリケーションを実行するには、Startボタンをクリックするか、Visual StudioでF5キーを押してテストしてください。
1:46:44の時点で、Timは再利用可能なメソッドの力を強調し、ファイルのロードと変換が"退屈"になったと言っていますが、それは良いことだと述べています。
彼はまず対戦エントリーを保存し、各エントリーにIDを付与します。その後、エントリーIDをパイプ区切りの文字列として保存する対戦自体を保存します。
さらに、DevExpress WinForms Subscriptionにはエンドユーザー向けのレポートデザイナーを備えたレポーティングスイートが含まれており、WinFormsアプリケーションを強化することができます。
マッチアップエントリーをデータベースに書き込む
1:49:43で、Timは節約ロジックを行単位で構築します。彼は慎重に以前の変換パターンを逆にします。
ID
TeamCompeting ID (または空の文字列)
スコア
- ParentMatchup ID (または空文字列)
保存ロジックを説明した後で、WinForms はさまざまな .NET プラットフォームでサポートされており、互換性と継続的な更新が保証されていることに注意することが重要です。
1:52:02 で、Tim は空の文字列が重要である理由を説明しています。それは、解析ロジックを壊さずに列の順序を保持するためです。
加えて、DevExpress WinFormsコントロールはDirectXハードウェアアクセラレーションをサポートし、パフォーマンスを向上させます。
試合と勝者の保存
1:55:02に、Timは試合自体を保存します。 試合は複数のエントリを持つことができるため、エントリリストを再利用可能なヘルパーメソッドを使用してパイプ区切りの文字列に変換します。 開発者はVisual Studioのツールボックスを使用して、ボタンやラベルなどのコントロールをWindows Formsに追加し、ユーザーインターフェースをデザインしやすくします。
1:58:30に、彼は勝者フィールドに同じヌル処理ロジックを適用します。 まだ勝者が存在しない場合、空の文字列が保存されます。
Windows Formsは、デスクトップ、タブレット、PCのアプリケーションを作成するための手段を開発者に提供します。
大会を読み込む際のラウンドの再構築
2:02:03に、Timは最後のTODOであるラウンド情報の読み込みに取り組みます。 彼はラウンドが試合IDのリストとして保存されており、最初にパイプで、次にキャレット(^)で分割されていると説明します。
2:09:13までに、彼は完全なネスト構造を再構築します:
ID → 試合モデル
試合モデル → ラウンドリスト
- ラウンドリスト → 大会モデル
再構築を説明した後、Timは、他のフレームワークとは異なり、WinFormsはUIとデータの構成方法が異なることを指摘し、これが開発者がネスト構造を管理する方法に影響を与える可能性があると述べます。
Timは、このネストがコードが複雑に感じられる理由であり、手動でステップスルーすることが非常に重要である理由を強調します。
また、DevExpress WinFormsサブスクリプションには、WinFormsアプリケーション用のカスタマイズ可能なテーマとスキンが含まれていることも言及に値します。
実際のエラーのデバッグ
2:11:22以降、Timは意図的にアプリを実行し、デバッグします:
NullReferenceException
入力文字列が正しい形式ではありません
- シーケンスに要素が含まれていません
間違いを隠すのではなく、Timはそれらをどのように追跡し、値を検査し、実行順序について理由を説明するかを正確に示します。 WinFormsは何年も前にリリースされ、時を経て進化してきました。
2:20:30に、彼は円形の保存問題を特定します:試合はエントリがそれらを参照する前に存在する必要がありました。 彼の解決策は実用的です—2回保存します。彼はそれがエレガントではないことを率直に認めますが、次のように言います:
"動作するコードは、バグを抱えたままのリファクタリングされたコードよりも優れています。"
Windows Formsは、.NET Core用のオープンソースプロジェクトとしてGitHubで利用可能です。
Windows Formsアプリの展開
Visual StudioでWindows Formsアプリのビルドとテストが完了した後、次のステップは展開です—アプリケーションをユーザーに利用可能にすることです。 Visual Studioは、Windowsデスクトップアプリケーション用に最も便利なオプションの一つであるClickOnceを含むいくつかのデプロイメントオプションを提供します。 ClickOnceを使用すると、アプリをネットワークファイル共有、ウェブサーバ、またはCD/DVDに公開でき、エンドユーザーのインストールが簡単になります。
デプロイするには、Visual Studioの公開ツールを使ってアプリをパッケージ化します。公開前に、Visual Studioのデバッグツールを使ってアプリケーションを徹底的にテストし、コード内のエラーや問題を検出して修正します。 デプロイ後、ユーザーはセットアップファイルを実行するかショートカットをクリックしてアプリをインストールでき、アプリが実行され、即座にインタラクション可能なグラフィカルユーザーインターフェイスを表示します。 ClickOnce、Windows Installer、またはサードパーティのデプロイメントツールを選択するかにかかわらず、そのプロセスにより、ユーザーが最小のトラブルでWindows Formsアプリの完全な機能と特徴にアクセスできることを保証します。 この合理化されたデプロイメントプロセスは、信頼性のあるプロフェッショナルなWindowsデスクトップアプリケーションを配信するのに役立ちます。
締めくくりの考え
このレッスンの終わりまでに、Tim Coreyはデータ永続化システムをテキストファイルをデータベースとして使用して完全に動作するものを実演します。 さらに重要なことに、彼は現実のバグがどのように発生し、パターンが修正をガイドし、なぜ実行順序の理解が完璧よりも重要であるかを示します。
このレッスンは派手なデータベースに関するものではなく、開発者のように考えることに関するものです。

